-
Notifications
You must be signed in to change notification settings - Fork 82
Writing Documentation
- Document everything. At least with at a
\brief
description. - Use British English.
- Qt-Style, i.e. documentation begins with
//!
or/*!
, not///
or/**
- Commands begin with
\
, not with@
- Use Markdown instead of doxygen specific constructs whenever possible! (E.G.
###
instead of\par
)
There are two "documentation targets", one for users of the library and one for developers of the library. See Setting up Documentation on how to build these targets.
Usually everything in the namespace seqan3
, seqan3::view
and seqan3::literal
shall be documented for the user and all documentation in these namespaces is visible to the user by default via the instructions above.
On the other hand all documentation in namespace seqan3::detail
, all private class members (static or not) and all code inside an #ifndef NDEBUG
block, are only included in the developer documentation (which is also the desired behaviour).
In the following situations you might want to restrict something to the developer documentation that would be in the user documentation by default:
-
protected
class members: often these are implementation detail, because the inheritance is only relevant to library developers. In this case insert a\privatesection
command at the beginning of the section in the code (this can be reverted by inserting a\publicsection
later again). -
public
non-static class data members of POD types: as per Classes and Structs PODTypes are preferable in many situations, but they don't allow you to make data members private. In these cases where you also gave a data member a_
prefix, you should also hide it from the user documentation by\privatesection
/\publicsection
- any other more sophisticated documentation aimed at developers, e.g. "When sub-classing the CRTP base class, remember to...": Wrap the region in
\cond DEV
followed by\endcond
later.
The order of entries in a documentation block shall be
- \TYPE (e.g
\file
,\class
...) [this is only required for\file
and if the definition is otherwise excluded] -
\brief Brief description.
[everything should always have this; ENDS WITH A FULL STOP] -
\ingroup (SUB-)MODULENAME
[every non-member shall provide this] -
\implements CONCEPT
[only structs/classes have this] -
\author FIRST_NAME SECOND_NAME EMAIL
[only files should have this] -
\tparam example_type Description of template parameter.
[Only templates have this. Should contain any constraints on the parameter, e.g.Must satisfy seqan3::alphabet_concept.
] -
\param[in] foo Description of foo parameters.
[Only functions have this, choose [in] or [out] or [in,out]] -
\details One-line detail comment.
OR
\details
Multi-line
Detailed description.
When documenting a class, make sure to group the members:
Member types
Constructors, destructor and assignment
-
Comparison operators
(if these behave as expected, it is sufficient to document only the group, not each operator!)
For structs that implement something a range, choose the same member groups as in the documentation on cppreference, e.g. std::vector:
Element access
Iterators
Capacity
Modifiers
All functions shall additionally provide the following paragraphs in their \details
section :
-
### Complexity
A statement on the complexity, with an O-notation term, e.g. (\f$O(1)\f$). -
### Exceptions
[The level of exception safety (see Exceptions). Independent of this any user defined exceptions possibly thrown, shall be annotated with\throws
before the\details
section] -
### Thread safety
The level of thread safety (see Thread Safety).
For member functions of a class the Thread safety
can be documented once inside the class, unless if the behaviour of a function is unexpected in this context of course.
Doxygen doesn't handle concepts at all, the current behaviour is:
- (variable) concept definition: Should be escaped completely and documented as an interface.
-
constrained templates: are usually handled ok, an exception are local definitions with
requires requires
which can cause problems and should be escaped with\cond
...\endcond
- constrained function templates: to prevent the entire requires clause from being added to the return type, move the required clause between function signature and body (instead of between template header and signature)
See Document Concepts for how to document concept definitions.
Examples:
//!\brief Value metafunction that returns the `value_size` defined inside an alphabet type.
//!\tparam alphabet_type Must provide a `value_size` static member.
template <typename alphabet_type>
//!\cond
requires requires (alphabet_type c) { alphabet_type::value_size; }
//!\endcond
struct alphabet_size
{
//!\brief The alphabet's size.
static constexpr underlying_rank_t<alphabet_type> value = alphabet_type::value_size;
};
# Documenting Concepts
A good workaround for doxygen not supporting concepts seems to be excluding them from the documentation build via `\cond` and `\nocond` and then just defining them via the [interface command](http://www.stack.nl/~dimitri/doxygen/manual/commands.html#cmdinterface). It is also possible to define the required functions on this concept as members or related functions of that concept.
Then we can also mark other types as `\implements concept_name` and have concepts that refine other concept specify `\extends other_concept`. This should provide for really nice documentation!
Here is an example of the alphabet_concept:
```cpp
/*!\interface seqan3::alphabet_concept <>
* \brief The generic alphabet concept that covers most data types used in ranges.
* \ingroup alphabet
*
* The requirements for this concept are given as related functions and metafunctions.
* Types that satisfy this concept are shown as "implementing this interface".
*/
/*!\fn auto seqan3::to_char(alphabet_concept const c)
* \brief Returns the alphabet letter's value in character representation.
* \relates seqan3::alphabet_concept
* \param c The alphabet letter that you wish to convert to char.
* \returns The letter's value in the alphabet's char type (seqan3::underlying_char).
* ...
*/
//!\cond
template <typename t>
concept bool alphabet_concept = requires (t t1, t t2)
{
// StL concepts
requires std::is_pod_v<t> == true;
requires std::is_swappable_v<t> == true;
// static data members
alphabet_size<t>::value;
// conversion to char and rank
{ to_char(t1) } -> underlying_char_t<t>;
{ to_rank(t1) } -> underlying_rank_t<t>;
{ std::cout << t1 };
// assignment from char and rank
{ assign_char(t1, 0) } -> t &;
{ assign_rank(t1, 0) } -> t &;
{ assign_char(t{}, 0) } -> t &&;
{ assign_rank(t{}, 0) } -> t &&;
// required comparison operators
{ t1 == t2 } -> bool;
{ t1 != t2 } -> bool;
{ t1 < t2 } -> bool;
{ t1 > t2 } -> bool;
{ t1 <= t2 } -> bool;
{ t1 >= t2 } -> bool;
};
//!\endcond