Developer/Guidelines

Developer/Guidelines

This document outlines guidelines and policies that should be followed in the process of development of Boost.Geometry.

It is aimed to propose Boost.Geometry to the collection of  Boost C++ Libraries, so it is intentional to closely follow Boost conventions. As such, this document is based on  Boost Library Requirements and Guidelines and  Boost Header Policy. In case of doubts in any subject, refer to Boost guidelines.

Headers include order

  1. C Standard Library (using C++ library names, i.e. <cstdlib>)
  2. C++ Standard Library (std namespace)
  3. Boost C++ Libraries (boost namespace)
  4. Boost.Geometry headers
  5. Other 3rd-party headers (only if applicable! in some samples only)

It's usually a good idea to keep headers ordered alphabetically within these sections, especially if there are many of headers.

Macros

All names of  preprocessor macros are always UPPER-CASE and words/tokens are separated with underscore (_). Macro identifiers must not begin with one or more underscores, such names are reserved according to the  C++ Language Standard. Generally, it's a good practice to avoid macros if you can and use them only when you have to.

Include guards

Names of  include guards are constructed as follows:

BOOST_GEOMETRY_<DIRECTORY 1>_<DIRECTORY N>_<FILE>_HPP

For example, header boost/geometry/strategies/distance_result.hpp is guarded as follows.

#ifndef BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP
#define BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP

// ...

#endif // BOOST_GEOMETRY_STRATEGIES_DISTANCE_RESULT_HPP

It is not necessary to append _INCLUDED postfix

Formatting

  • Use spaces in all source files. Strictly, no tabs.
  • Prefered line length is 80 characters, however maximum is 100 characters in line.
  • Do not indent namespace blocks.
  • Prefer readable formatting and indentation of long template definition. Possible indentation layout is presented below:
template
<
    typename T,
    typename P,
    typename C = std::vector<Point>
>
struct polygon
{
    typedef typename boost::remove_const
        <
            typename traits::point_type<T>::type
        >::type type
};

Naming convention

  • Use m_ prefix for member variables as readable form. The Boost  sample header gives no prefix/suffix at all. However, the m_ prefix is used in some (not many) boost libraries as well (e.g. math/tools/remez).
  • Do not prefix or postfix any names with underscore.

Miscellaneous

  • Keyword struct is preferred either for POD structures, or for classes used at compile-time like metafunctions, tags, traits, etc.
  • Keyword class is preferred for classes meant to produce actual objects, which have methods and an active role in the runtime functioning of the program.
  • In case of a template, prefer use of typename keyword over class.
  • Order access specifiers for class members as public first, then protected and private at the bottom. The public members define class interface, thus they are of the highest interested for users, so show them first.
  • Exceptions are possible for typedef aliases required to be defined first.
  • For references to const object, the const qualifier is placed after the type and it's a good idea to follow this guideline for pointer to const object - it read it right to left:
    Point const& point;
    
    void foo(Point const* point);
    

Example

Guidelines summary example:

namespace boost { namespace geometry
{

namespace a
{

template <typename T>
struct sample1
{
    typedef T type;
};

template <typename T>
class sample2
{
public:

    sample2(T a, T b) : m_a(a), m_b(b) {}
    void foo() {}

protected:

    void bar() {}

private:

    T m_a;
    T m_b;
}; 

} // namespace a
}} // namespace boost::geometry

Dispatching and specializations

  • Algorithms are free inline functions, taking any geometry. Parameters are often one or two geometries
  • There might be an overload for a strategy. The strategy takes, a.o. care of coordinate systems
  • The free inline function forwards to a dispatch struct, specialized for the geometry type (so for point, polygon, etc)
  • They have an static (inline) function called apply
  • All template parameters are in the struct, so no member template functions there
  • The dispatch struct calls, or is derived from, an struct implemented in namespace detail
  • There the same: a struct with a static (inline) function called apply
  • This way the implementation structs are building blocks, they can be reused
  • In fact they are reused often by the multi-versions of the algorithms

Example

Example for simple structs


namespace boost { namespace geometry
{

namespace detail { namespace foo 
{


template <typename Point>
struct foo_point
{
    // template parameters here
    static inline int apply(Point const& p) 
    { 
        // do something here
        return 1; 
    }
};


}} // namespace detail::foo


namespace dispatch 
{


template <Tag, Geometry>
struct foo
{
};


// Specialization for POINT
template <typename Point>
struct foo<point_tag, Point>
    : detail::foo::foo_point<Point>
{};


// Specialization for polygon
template <typename Polygon>
struct foo<polygon_tag, Polygon>
    : detail::foo::foo_polygon<Polygon>
{};


} // namespace dispatch


template <typename Point>
inline int foo(Point const& point)
{
    return dispatch<typename tag<Point>::type, Point>::apply(point);
}


}} // namespace boost::geometry

Developer