removed some useless spaces; not very important, I know :)
[senf.git] / Socket / SocketPolicy.hh
1 // $Id:SocketPolicy.hh 218 2007-03-20 14:39:32Z tho $
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Policy Framework public header
25
26     \idea Creating a new Socket will create 3 new instances (The handle, the body, the policy) of
27         which 2 (argh) (body, policy) live on the heap. This is expensive. We should convert all the
28         policy classes to singletons and assign the same instance to all socket bodies with the same
29         policy. This would reduce the number of heap allocations per socket handle to one (which is
30         already optimized using the pool_alloc_mixin)
31  */
32
33 /** \defgroup policy_group The Policy Framework
34
35     \htmlonly
36         <map name="socketPolicy">
37           <area shape="rect" alt="SocketPolicy" href="structsenf_1_1SocketPolicy.html" title="SocketPolicy" coords="276,90,558,213" />
38           <area shape="rect" alt="WritePolicyBase" href="structsenf_1_1WritePolicyBase.html" title="WritePolicyBase" coords="39,243,174,268" />
39           <area shape="rect" alt="ReadPolicyBase" href="structsenf_1_1ReadPolicyBase.html" title="ReadPolicyBase" coords="42,204,174,231" />
40           <area shape="rect" alt="CommunicationPolicyBase" href="structsenf_1_1CommunicationPolicyBase.html" title="CommunicationPolicyBase" coords="0,166,215,193" />
41           <area shape="rect" alt="FramingPolicyBase" href="structsenf_1_1FramingPolicyBase.html" title="FramingPolicyBase" coords="30,129,185,155" />
42           <area shape="rect" alt="AddressingPolicyBase" href="structsenf_1_1AddressingPolicyBase.html" title="AddressingPolicyBase" coords="17,90,200,116" />
43         </map>
44         <img src="SocketPolicy.png" border="0" alt="Socket Policy" usemap="#socketPolicy">
45     \endhtmlonly
46         
47     \section policy_group_introduction Introduction to the Policy Framework
48
49     The policy framework conceptually implements a list of parallel inheritance hierarchies each
50     covering a specific interface aspect of the socket handle. The socket handle itself only
51     provides minimal functionality. All further functionality is relayed to a policy class, or more
52     precisely, to a group of policy classes, one for each policy axis. The policy axis are
53
54     <dl><dt><em>addressingPolicy</em></dt><dd>configures, whether a socket is addressable and if
55     so, configures the address type</dd>
56
57     <dt><em>framingPolicy</em></dt> <dd>configures the type of framing the socket provides: either
58     no framing providing a simple i/o stream or packet framing</dd>
59
60     <dt><em>communicationPolicy</em></dt><dd>configures,if and how the communication partner is
61     selected</dd>
62
63     <dt><em>readPolicy</em></dt><dd>configures the readability of the socket</dd>
64
65     <dt><em>writePolicy</em></dt><dd>configures the writability of the socket</dd>
66
67     The template senf::SocketPolicy combines these policy axis to form a concrete socket policy. In
68     a concrete policy, each of these policy axis is assigned a value, the policy value. This value
69     is identified by a class type, a policy class. E.g. possible values for <em>framingPolicy</em>
70     are <tt>DatagramFramingPolicy</tt> or <tt>StreamFramingPolicy</tt> which are classes derived
71     from the axis base class <tt>FramingPolicyBase</tt>. This base class also doubles as
72     <tt>UnspecifiedFramingPolicy</tt> (which is just a typedef alias).  If a policy axis is assigned
73     this Unspecified type, the axis is left unspecified, the concrete policy will be incomplete.
74     
75     The senf::SocketPolicy template defines the behavior of a socket handle. The socket handle
76     instances do not implement any socket functionality themselves instead deferring the
77     implementation to the policy classes. The SocketHandle interface is therefore \e not implemented
78     using virtual members, all important socket functions can be inlined by the compiler to create
79     highly efficient code.
80
81     A senf::SocketPolicy instance can be incomplete. In this case it does \e not completely specify
82     the socket interface, it leaves some aspects open by assigning the Unspecified value to one or
83     more of the policy axis. A senf::SocketHandle based on such a policy will have a reduced
84     interface: It will only support those members for which the corresponding policies are defined.
85
86     To build a senf::SocketPolicy instance the senf::MakeSocketPolicy helper is provided. This
87     helper template takes any number (it is really limited to 6 Arguments but more arguments don't
88     make sense) of policy classes as it's argument. The MakeSocketPolicy helper will take the
89     arguments in the order they are specified and for each argument will check to which axis the
90     policy class belongs (by checking the base classes of that class) and assign it to the correct
91     policy axis in the senf::SocketPolicy template. If any policy axis are not specified, they are
92     defaulted to their corresponding Unspecified value. This helper frees you to specify the policy
93     classes in any order. An additional feature is, that you may specify a complete policy as a
94     first argument. This policy will then be used to provide default values for unspecified axis.
95
96     Two senf::SocketHandle's with different policies can be \e compatible. If they are, the more
97     specific SocketHandle can be converted (assigned to) the more basic SocketHandle. A SocketHandle
98     is more specific then another SocketHandle if the policy of the former is more specific then
99     that of the latter which means, that for each policy axis separately, the value of that axis of
100     the more specific policy is derived from or the same as the value of that axis in the more basic
101     policy. This is like converting a derived class pointer to a base class pointer, only it happens
102     separately but at the same time for each policy axis:
103
104     \code
105     // This defines an incomplete policy where addressingPolicy and writePolicy
106     // are unspecified
107     typedef senf::MakeSocketPolicy<
108         senf::StreamFramingPolicy,
109         senf::ConnectedCommunicationPolicy,
110         senf::ReadablePolicy
111         >::policy MyReadableSocketPolicy
112
113     typedef senf::ClientSocketHandle<MyReadableSocketPolicy> MyReadableHandle;
114
115     // TCPv4ClientSocketHandle is a socket handle with the policy equivalent to
116     // senf::MakeSocketPolicy<
117     //     INet4AddressingPolicy,
118     //     StreamFramingPolicy,
119     //     ConnectedCommunicationPolicy,
120     //     ReadablePolicy,
121     //     WritablePolicy>::policy
122     senf::TCPv4ClientSocketHandle tcpHandle (...);
123
124     MyReadableHandle myHandle (tcpHandle); // Conversion to more basic socket handle
125     \endcode
126
127     \section policy_group_details The Policy Framework Classes
128
129     In the following discussion, deeper insight into C++ and especially the concepts of template
130     meta-programming are needed. However, this information is only needed if you want to write new
131     policy classes or want to use the policy framework explicitly for your own involved
132     optimizations ... or if you are just plain curious :-)
133     
134     In the following discussion we will use the following conventions:
135     \li \e Axis is one or \c AddressingPolicy, \c FramingPolicy, \c CommunicationPolicy, \c
136         ReadPolicy or \c WritePolicy
137     \li \e socketPolicy is any socket policy (that is, an instantiation of the SocketPolicy
138         template)
139     \li \e trait is an any policy class (that is, any class derived from one of the axis base
140         classes)
141
142     Each axis is comprised of a number of classes and templates (all in namespace senf of course):
143
144     <dl><dt>\e Axis \c Base (ex: AddressingPolicyBase)</dt><dd>Baseclass of all policies in this
145     axis</dd>
146
147     <dt>\c Unspecified \e Axis (ex: \ref UnspecifiedAddressingPolicy)</dt> <dd>An alias (typedef)
148     for \e Axis \c Base</dd>
149
150     <dt>\e Axis \c Is < \e socketPolicy, \e trait > (ex: AddressingPolicyIs)</dt> <dd>A template
151     metafunction returning \c boost::true_type, if \e trait (any class derived from \e Axis \c
152     Base) is a compatible policy value of the given \e socketPolicy</dd>
153
154     <dt>\c If \e Axis \c Is < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIs)</dt> <dd>This
155     is a combination of \e Axis \c Is and \c boost::enable_if</dd>
156
157     <dt>\c If \e Axis \c IsNot < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIsNot)</dt>
158     <dd>The inverse of above</dd> </dl>
159
160     These classes form the basis of the policy framework. To bind the policy axis together, there
161     are some more classes and templates.
162
163     <dl><dt>\c class \c SocketPolicyBase</dt> <dd>This class is the base class of the SocketPolicy
164     template. It is used to validate, that a class is really a SocketPolicy (by checking, that it
165     derives from SocketPolicyBase. This is simpler than checking the template directly).</dd>
166
167     <dt>\c template \c SocketPolicy < \e addressingPolicy, \e framingPolicy, \e communicationPolicy,
168     \e readPolicy, \e writePolicy ></dt> <dd>This is the central SocketPolicy
169     template. It combines a complete set of policy classes, one for each axis.</dd>
170
171     <dt>\c template \c MakeSocketPolicy < \e args ></dt> <dd>\c MakeSocketPolicy is a template
172     metafunction which simplifies building SocketPolicy instantiations. It takes any number (ok, up
173     to a maximum of 6) of policy classes as an argument (in any order). It will sort these arguments
174     into the SocketPolicy template arguments. If for some axis no class is specified, it's slot will
175     be filled with \c Unspecified \e Axis. Additionally, the first Argument may optionally be ab
176     arbitrary SocketPolicy. It will provide default values for unspecified axis</dd>
177
178     <dt>\c template \c SocketPolicyIsBaseOf < \e base, \e derived ></dt> <dd>This template
179     metafunction will check, whether the socket policy \e derived is convertible to \e base. This
180     means, that for each axis, the corresponding policy class in \e derived must be derived or be
181     the same as the one on \e base.</dd> </dl>
182
183     \implementation All these classes are created automatically. The \c SENF_SOCKET_POLICIES macro
184     is a Boost.Preprocessor style sequence listing all policy axis. The Boost.Preprocessor library
185     is then used to generate the respective classes.
186
187     \section policy_implement Implementing Policy Classes
188
189     To define a new policy class, derive from the corresponding base class for your policy axes. The
190     only policy axis which might possibly need to be extended is the addressing policy
191     (AddressingPolicyBase). See the Documentation of these classes for more information on which
192     members can be implemented.
193
194     All members you define must be static. For any of the policy classes, you must only define those
195     members which are supported by your implementation. If you leave out a member you automatically
196     disable the corresponding functionality in the ClientSocketHandle/ServerSocketHandle interface.
197
198     The member prototypes given in the base class documentation only specify the call signature not
199     the way, the member must be defined (FileHandle really is not a FileHandle but an arbitrary
200     SocketHandle).
201
202     If the existence of a member depends on other policies, you should use the
203     <code>If</code><i>SomePolicy</i><code>Is</code> and
204     <code>If</code><i>SomePolicy</i><code>IsNot</code> templates to dynamically enable/disable the
205     member depending on some other policy:
206
207     \code
208       struct ExampleAddressingPolicy
209       {
210           template <class SPolicy>
211           void connect(senf::SocketHandle<SPolicy> handle, Address & addr,
212                        typename senf::IfCommmunicationPolicyIs<
213                            SPolicy, senf::ConnectedCommunicationPolicy>::type * = 0);
214       };
215     \endcode
216
217     The \c connect member in this example will only be enabled, it the communication policy of the
218     socket handle is ConnectedCommunicationPolicy (or a derived type). See <a
219     href="http://www.boost.org/libs/utility/enable_if.html">Boost.Enable_If</a> for a discussion of
220     the third argument (\c senf::ConnectedCommunicationPolicyIs is based on the \c boost::enable_if
221     template).
222
223     \see \ref extend_policy \n
224          <a href="http://www.boost.org/libs/utility/enable_if.html">The Boost enable_if utility</a> \n
225          <a href="http://www.boost.org/libs/mpl/doc/index.html">The Boost.MPL library</a> \n
226          <a href="http://www.boost.org/libs/preprocessor/doc/index.html">The Boost.Preprocessor library</a>
227
228     \idea We could combine all the \e Axis \c Is templates into a single template. Since the \e
229     trait argument will automatically specify the axis to be used, it is not necessary to specify
230     that axis in the template functor's name. We could even combine this with \c
231     SocketPolicyIsBaseOf.
232  */
233
234 /** \defgroup policy_impl_group Policy Implementation classes
235     \ingroup policy_group
236
237     Here you will find all policy classes. Also included are some supporting classes which are used
238     as base classes to build other policy classes.
239  */
240
241 #ifndef HH_SocketPolicy_
242 #define HH_SocketPolicy_ 1
243
244 // Custom includes
245
246 //#include "SocketPolicy.mpp"
247 ///////////////////////////////hh.p////////////////////////////////////////
248
249 namespace senf {
250
251     /// \addtogroup policy_group
252     /// @{
253
254     // This may be adapted to change the supported policies (however, ClientSocketHandle and
255     // ServerSocketHandle will probably have to be adjusted accordingly)
256
257     /** \brief List all policy axis
258
259         \internal
260
261         This define symbol is used to configure the policy axis. The base class for each of these
262         axis must be defined explicitly (e.g. AddressingPolicyBase). The implementation files will
263         then automatically generate all the other classes from this list.
264
265         \see policy_group
266      */
267 #   define SENF_SOCKET_POLICIES                 \
268         (AddressingPolicy)                      \
269         (FramingPolicy)                         \
270         (CommunicationPolicy)                   \
271         (ReadPolicy)                            \
272         (WritePolicy)
273
274     // Wer define these classes explicitly (and not with some macro
275     // magic) because
276     // a) AddressingPolicyBase is different from all the others
277     // b) We want to document each one explicitly
278
279     /** \brief Policy defining socket addressing
280
281         AddressingPolicyBase is the baseclass of all addressing policy classes. When defining a new
282         addressing policy, the following members can be defined. All methods must be static.
283
284         <table class="senf">
285         <tr><td>typedef</td> <td><tt>Address</tt></td>                                   <td>Address type</td></tr>
286         <tr><td>method</td>  <td><tt>void local(FileHandle, Address &)</tt></td>         <td>Get local socket address</td></tr>
287         <tr><td>method</td>  <td><tt>void peer(FileHandle, Address &)</tt></td>          <td>Get remote socket address</td></tr>
288         <tr><td>method</td>  <td><tt>void bind(FileHandle, Address const &)</tt></td>    <td>Bind socket to local address</td></tr>
289         <tr><td>method</tr>  <td><tt>void connect(FileHandle, Address const &)</tt></td> <td>Connect to remote address</td></tr>
290         </table>
291
292         \see policy_group
293      */
294     struct AddressingPolicyBase
295     {
296         virtual ~AddressingPolicyBase() {}
297
298         class Address { Address(); };
299     };
300
301     /** \brief Policy defining the framing format
302
303         This policy does not define any operations since it does have no influence on any method
304         signature. It does however affect the semantics of the \c read() and \c write() operations.
305
306         \note This policy axis probably only has two sensible states: StreamFramingPolicy and
307         DatagramFramingPolicy.
308
309         \see policy_group
310      */
311     struct FramingPolicyBase
312     {
313         virtual ~FramingPolicyBase() {}
314     };
315
316     /** \brief Policy defining, how peers are selected
317
318         The CommunicationPolicy may define two members:
319
320         <table class="senf">
321         <tr><td>method</td> <td><tt>void listen(FileHandle, unsigned backlog)</tt></td> <td>Switch socket into listening state</td></tr>
322         <tr><td>method</td> <td><tt>int accept(FileHandle, Address &)</tt></td>         <td>Accept a new connection</td></tr>
323         <tr><td>method</td> <td><tt>int accept(FileHandle)</tt></td>                    <td>Accept a new connection</td></tr>
324         </table>
325
326         The \c listen member is straight forward. The \c accept() member must return a new file
327         descriptor (which will be used to create a new SocketHandle of the correct
328         type). 
329
330         \note This Policy only has two meaningful states: ConnectedCommunicationPolicy and
331         UnconnectedCommunicationPolicy. It is probably not sensible to define a new
332         CommunicationPolicy type.
333
334         \see policy_group
335      */
336     struct CommunicationPolicyBase
337     {
338         virtual ~CommunicationPolicyBase() {}
339     };
340
341     /** \brief Policy defining the readability
342
343         The ReadPolicy defines, whether the socket is readable. It may define two members:
344
345         <table class="senf">
346         <tr><td>method</td> <td><tt>unsigned read(FileHandle, char * buffer, unsigned size)</tt></td>                <td>read data from socket</td></tr>
347         <tr><td>method</td> <td><tt>unsigned readfrom(FileHandle, char * buffer, unsigned size, Address &)</tt></td> <td>read data from unconnected socket</td></tr>
348         </table>
349
350         The second member should only be enabled if the communication policy is
351         UnconnectedCommunicationPolicy (otherwise it does not make sense since the communication partner
352         is fixed) (see AddressingPolicyBase on how to do this).
353
354         \note This Policy only has two meaningful states: ReadablePolicy and NotReadablePolicy. It
355         probably does not make sense to define new read policy types.
356
357         \see policy_group
358      */
359     struct ReadPolicyBase
360     {
361         virtual ~ReadPolicyBase() {}
362     };
363
364     /** \brief Policy defining the writability
365
366         The WritePolicy defines, whether the socket is writable. It may define two members:
367
368         <table class="senf">
369         <tr><td>method</td> <td><tt>unsigned write(FileHandle, char * buffer, unsigned size)</tt></td>              <td>read data from socket</td></tr>
370         <tr><td>method</td> <td><tt>unsigned writeto(FileHandle, char * buffer, unsigned size, Address &)</tt></td> <td>read data from unconnected socket</td></tr>
371         </table>
372
373         The second member should only be enabled if the communication policy is
374         UnconnectedCommunicationPolicy (otherwise it does not make sense since the communication partner
375         is fixed) (see AddressingPolicyBase on how to do this).
376
377         \note This Policy only has two meaningful states: WritablePolicy and NotWritablePolicy. It
378         probably does not make sense to define new write policy types.
379
380         \see policy_group
381      */
382     struct WritePolicyBase
383     {
384         virtual ~WritePolicyBase() {}
385     };
386
387     // The implementation file will for each Policy declared above
388     // define the following (SomePolicy is one of the above):
389     //
390     // struct SomePolicyBase;
391     // typedef UndefinedSomePolicy;
392     // template SomePolicyIs< SocketPolicy, Axis >
393     // template IfSomePolicyIs< SocketPolicy, Axis >
394     // template IfSomePolicyIsNot< SocketPolicy, Axis >
395     //
396     // Additionally the following are defined:
397     //
398     // class SocketPolicyBase
399     // template SocketPolicy< ..policies.. >
400     // template MakeSocketPolicy< ..args.. >
401     // template SocketPolicyIsBaseOf< Base, Derived >
402
403 #   ifdef DOXYGEN
404
405     // The following stub definitions are only visible to doxygen
406
407     /** \brief Alias of AddressingPolicyBase for better readability
408         \see \ref policy_group
409      */
410     typedef AddressingPolicyBase UnspecifiedAddressingPolicy;
411
412     /** \brief Check single policy axis
413
414         This template is an example of the \e Axis \c Is family of template metafunctions. It will
415         check, whether \c Trait is a valid compatible Policy class of \c SocketPolicy. \c Trait must
416         be derived from AddressingPolicyBase (respectively \c Policy \c Base).
417
418         \see \ref policy_group
419      */
420     template <class SocketPolicy, class Trait>
421     struct AddressingPolicyIs
422     {};
423
424     /** \brief Enable template overload depending on policy value
425
426         This template is an example of the \c If \e Axis \c Is family of templates. It is used like
427         <a href="http://www.boost.org/libs/utility/enable_if.html">Boost.enable_if</a> to enable a
428         templated overload only, if the AddressingPolicy of \e Axis is compatible with \c Trait
429         (that is the AddressingPolicy of \c Policy is derived from \c Trait).
430
431         \see policy_group
432      */
433     template <class SocketPolicy, class Trait>
434     struct IfAddressingPolicyIs
435     {};
436
437     /** \brief Inversion of \c IfAddressingPolicyIs
438         \see policy_group
439      */
440     template <class SocketPolicy, class Trait>
441     struct IfAddressingPolicyIsNot
442     {};
443
444     /** \brief Baseclass of all SocketPolicies
445
446         \internal
447
448         This class provides the baseclass of all socket policies (bundles). It serves two purposes:
449         \li It allows us to easily identify a socket policy bundle by checking a classes baseclass.
450         \li It provides an abstract (virtual) interface to access the policy axes
451
452         \see policy_group
453      */
454     struct SocketPolicyBase
455     {
456         /** \brief Polymorphic access to policy axes
457
458             This is an example of a policy axes accessor. It returns a reference to the policy axes
459             used by the concrete protocol bundle. This reference can then be checked using RTTI
460             information.
461          */
462         AddressingPolicyBase const & theAddressingPolicy() const = 0;
463     };
464
465     /** \brief Collection of policy classes
466
467         The SocketPolicy template defines the complete Policy used by the socket library. It
468         contains one policy class for each policy axis. This template takes one policy from each
469         axis as it's template arguments (this example implementation only has AddressingPolicy as an
470         argument).
471
472         A SocketPolicy can be complete or incomplete. An incomplete SocketPolicy will have at least
473         one axis set to \c Undefined \e Axis (or a generic derived class which is used to group some
474         other policies but does not (completely) define the policy behavior). A complete
475         SocketPolicy will have a concrete definition of the desired behavior for each policy axis.
476
477         \see policy_group
478      */
479     template < class AddressingPolicy >
480     struct SocketPolicy
481     {
482         /** \brief Check dynamic policy compatibility
483
484             This check will validate, that a socket with \a other as it's policy is convertible to a
485             socket with the current SocketPolicy as it's policy. This is true, if for each policy
486             axis, the policy class of that axis as defined in the \a other policy is convertible to
487             the policy class of that same axis in the current SocketPolicy instance (as is defined
488             by the template arguments). This again is true, if the \a other policy class is derived
489             from (or is the same as) the policy class taken from the current SocketPolicy instance.
490
491             In other words, this call checks, that the current SocketPolicy (as defined via the
492             template arguments) is more generic than the \a other socket policy.
493
494             \param[in] other SocketPolicy to check
495             \throws std::bad_cast if \a other is not a compatible policy
496          */
497         static void checkBaseOf(SocketPolicyBase const & other);
498     };
499
500     /** \brief Metafunction to create SocketPolicy
501
502         This template metafunction simplifies the creation of a SocketPolicy instantiation. It takes
503         any number (that is up to 6) of Policy classes as arguments in any Order. It will create a
504         SocketPolicy from these policy classes. Any axis not specified will be left as \c
505         Unspecified \e Axis.
506
507         \see policy_group
508      */
509     template <class Arg1, class Arg2, class ArgN>
510     struct MakeSocketPolicy
511     {};
512
513     /** \brief Check policy compatibility
514
515         This template metafunction checks, whether the SocketPolicy \c Derived is more specialized
516         than \c Base (and therefore a SocketHandle with policy \c Derived is convertible to a
517         SocketHandle with policy \c Base).
518
519         The metafunction will return true (that is inherits from \c boost::true_type, see the <a
520         href="http://www.boost.org/libs/mpl/doc/index.html">Boost.MPL</a> library documentation for
521         more information) if each policy class in \c Base is a baseclass of (or the same as) the
522         corresponding policy class in \c Derived.
523
524         \see policy_group
525      */
526     template <class Base, class Derived>
527     struct SocketPolicyIsBaseOf
528     {};
529
530 #   endif
531
532     /// @}
533 }
534
535 //////////////////////////////hh.e////////////////////////////////////////
536 #include "SocketPolicy.ih"
537 //#include "SocketPolicy.cci"
538 #include "SocketPolicy.ct"
539 //#include "SocketPolicy.cti"
540 #endif
541
542 \f
543 // Local Variables:
544 // mode: c++
545 // fill-column: 100
546 // c-file-style: "senf"
547 // indent-tabs-mode: nil
548 // ispell-local-dictionary: "american"
549 // compile-command: "scons -u test"
550 // comment-column: 40
551 // End: