text:
// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2008 Steven Watanabe
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

/**
\file

\brief systems.cpp

\details
Test various non-si units

Output:
@verbatim

@endverbatim
**/

#define BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(namespace_,unit_name_,dimension_)              \
namespace boost {                                                                            \
namespace units {                                                                            \
namespace namespace_ {                                                                       \
typedef make_system<unit_name_ ## _base_unit>::type    unit_name_ ## system_;                \
typedef unit<dimension_ ## _dimension,unit_name_ ## system_> unit_name_ ## _ ## dimension_;  \
static const unit_name_ ## _ ## dimension_    unit_name_ ## s;                               \
}                                                                                \
}                                                                                \
}                                                                                \

#include <iostream>
#include <sstream>
#include <algorithm>

#include <boost/units/conversion.hpp>
#include <boost/units/io.hpp>
#include <boost/units/pow.hpp>

#include <boost/units/systems/cgs.hpp>
#include <boost/units/systems/si.hpp>

// angle base units
#include <boost/units/base_units/angle/arcminute.hpp>
#include <boost/units/base_units/angle/arcsecond.hpp>
#include <boost/units/base_units/angle/degree.hpp>
#include <boost/units/base_units/angle/gradian.hpp>
#include <boost/units/base_units/angle/revolution.hpp>
#include <boost/units/base_units/angle/radian.hpp>
#include <boost/units/base_units/angle/steradian.hpp>

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,arcminute,plane_angle)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,arcsecond,plane_angle)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,degree,plane_angle)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,gradian,plane_angle)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,radian,plane_angle)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,revolution,plane_angle)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(angle,steradian,solid_angle)

// astronomical base units
#include <boost/units/base_units/astronomical/astronomical_unit.hpp>
#include <boost/units/base_units/astronomical/light_second.hpp>
#include <boost/units/base_units/astronomical/light_minute.hpp>
#include <boost/units/base_units/astronomical/light_hour.hpp>
#include <boost/units/base_units/astronomical/light_day.hpp>
#include <boost/units/base_units/astronomical/light_year.hpp>
#include <boost/units/base_units/astronomical/parsec.hpp>

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,astronomical_unit,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,light_second,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,light_minute,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,light_hour,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,light_day,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,light_year,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(astronomical,parsec,length)

// imperial base units
#include <boost/units/base_units/imperial/thou.hpp>
#include <boost/units/base_units/imperial/inch.hpp>
#include <boost/units/base_units/imperial/foot.hpp>
#include <boost/units/base_units/imperial/yard.hpp>
#include <boost/units/base_units/imperial/furlong.hpp>
#include <boost/units/base_units/imperial/mile.hpp>
#include <boost/units/base_units/imperial/league.hpp>

#include <boost/units/base_units/imperial/grain.hpp>
#include <boost/units/base_units/imperial/drachm.hpp>
#include <boost/units/base_units/imperial/ounce.hpp>
#include <boost/units/base_units/imperial/pound.hpp>
#include <boost/units/base_units/imperial/stone.hpp>
#include <boost/units/base_units/imperial/quarter.hpp>
#include <boost/units/base_units/imperial/hundredweight.hpp>
#include <boost/units/base_units/imperial/ton.hpp>

#include <boost/units/base_units/imperial/fluid_ounce.hpp>
#include <boost/units/base_units/imperial/gill.hpp>
#include <boost/units/base_units/imperial/pint.hpp>
#include <boost/units/base_units/imperial/quart.hpp>
#include <boost/units/base_units/imperial/gallon.hpp>

#include <boost/units/base_units/imperial/conversions.hpp>

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,thou,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,inch,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,foot,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,yard,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,furlong,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,mile,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,league,length)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,grain,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,drachm,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,ounce,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,pound,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,stone,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,quarter,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,hundredweight,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,ton,mass)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,fluid_ounce,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,gill,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,pint,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,quart,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(imperial,gallon,volume)

// metric base units
#include <boost/units/base_units/metric/angstrom.hpp>
#include <boost/units/base_units/metric/fermi.hpp>
#include <boost/units/base_units/metric/micron.hpp>
#include <boost/units/base_units/metric/nautical_mile.hpp>

#include <boost/units/base_units/metric/ton.hpp>

#include <boost/units/base_units/metric/day.hpp>
#include <boost/units/base_units/metric/hour.hpp>
#include <boost/units/base_units/metric/minute.hpp>
#include <boost/units/base_units/metric/year.hpp>

#include <boost/units/base_units/metric/knot.hpp>

#include <boost/units/base_units/metric/are.hpp>
#include <boost/units/base_units/metric/barn.hpp>
#include <boost/units/base_units/metric/hectare.hpp>

#include <boost/units/base_units/metric/liter.hpp>

#include <boost/units/base_units/metric/atmosphere.hpp>
#include <boost/units/base_units/metric/bar.hpp>
#include <boost/units/base_units/metric/mmHg.hpp>
#include <boost/units/base_units/metric/torr.hpp>

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,angstrom,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,fermi,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,micron,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,nautical_mile,length)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,ton,mass)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,day,time)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,hour,time)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,minute,time)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,year,time)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,knot,velocity)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,are,area)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,barn,area)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,hectare,area)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,liter,volume)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,atmosphere,pressure)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,bar,pressure)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,mmHg,pressure)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(metric,torr,pressure)

// us base units

#include <boost/units/base_units/us/mil.hpp>
#include <boost/units/base_units/us/inch.hpp>
#include <boost/units/base_units/us/foot.hpp>
#include <boost/units/base_units/us/yard.hpp>
#include <boost/units/base_units/us/mile.hpp>

#include <boost/units/base_units/us/grain.hpp>
#include <boost/units/base_units/us/dram.hpp>
#include <boost/units/base_units/us/ounce.hpp>
#include <boost/units/base_units/us/pound.hpp>
#include <boost/units/base_units/us/hundredweight.hpp>
#include <boost/units/base_units/us/ton.hpp>

#include <boost/units/base_units/us/minim.hpp>
#include <boost/units/base_units/us/fluid_dram.hpp>
#include <boost/units/base_units/us/teaspoon.hpp>
#include <boost/units/base_units/us/tablespoon.hpp>
#include <boost/units/base_units/us/fluid_ounce.hpp>
#include <boost/units/base_units/us/gill.hpp>
#include <boost/units/base_units/us/cup.hpp>
#include <boost/units/base_units/us/pint.hpp>
#include <boost/units/base_units/us/quart.hpp>
#include <boost/units/base_units/us/gallon.hpp>

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,mil,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,inch,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,foot,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,yard,length)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,mile,length)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,grain,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,dram,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,ounce,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,pound,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,hundredweight,mass)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,ton,mass)

BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,minim,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,fluid_dram,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,teaspoon,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,tablespoon,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,fluid_ounce,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,gill,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,cup,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,pint,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,quart,volume)
BOOST_UNITS_DEFINE_SINGLE_UNIT_SYSTEM(us,gallon,volume)

#ifdef __GNUC__
#include <cxxabi.h>
#endif

inline std::string demangle(const char* name)
{
    #ifdef __GNUC__
    // need to demangle C++ symbols
    char*       realname;
    std::size_t len;
    int         stat;

    realname = abi::__cxa_demangle(name,NULL,&len,&stat);

    if (realname != NULL)
    {
        const std::string    out(realname);
        free(realname);

        return out;
    }

    return std::string("demangle :: error - unable to demangle specified symbol");
    #else
    return name;
    #endif
}

int main(void)
{
    using namespace boost::units;

    {
        using namespace boost::units::angle;

        std::cout << "Testing angle base units..." << std::endl;

        quantity<arcsecond_plane_angle>        as(1.0*arcseconds);
        quantity<arcminute_plane_angle>        am(1.0*arcminutes);
        quantity<degree_plane_angle>        d(1.0*degrees);
        quantity<gradian_plane_angle>        g(1.0*gradians);
        quantity<radian_plane_angle>        r(1.0*radians);
        quantity<revolution_plane_angle>    rev(1.0*revolutions);

        std::cout << as << " = " << quantity<si::plane_angle>(as) << std::endl
                  << am << " = " << quantity<si::plane_angle>(am) << std::endl
                  << d << " = " << quantity<si::plane_angle>(d) << std::endl
                  << g << " = " << quantity<si::plane_angle>(g) << std::endl
                  << r << " = " << quantity<si::plane_angle>(r) << std::endl
                  << rev << " = " << quantity<si::plane_angle>(rev) << std::endl
                  << std::endl;

        std::cout << rev << "/" << as << " = " << quantity<si::dimensionless>(rev/as) << std::endl
                  << rev << "/" << am << " = " << quantity<si::dimensionless>(rev/am) << std::endl
                  << rev << "/" << d << " = " << quantity<si::dimensionless>(rev/d) << std::endl
                  << rev << "/" << g << " = " << quantity<si::dimensionless>(rev/g) << std::endl
                  << rev << "/" << r << " = " << quantity<si::dimensionless>(rev/r) << std::endl
                  << std::endl;

        // conversions only work with exponent of +/- 1 in scaled_base_unit?
        std::cout << as << " = " << quantity<arcsecond_plane_angle>(as) << std::endl
                  << am << " = " << quantity<arcsecond_plane_angle>(am) << std::endl
                  << d << " = " << quantity<arcsecond_plane_angle>(d) << std::endl
                  << rev << " = " << quantity<arcsecond_plane_angle>(rev) << std::endl
                  << std::endl;

        // conversions only work with exponent of +/- 1 in scaled_base_unit? see arcsecond.hpp
        std::cout << as << " = " << quantity<arcminute_plane_angle>(as) << std::endl
                  << am << " = " << quantity<arcminute_plane_angle>(am) << std::endl
                  << d << " = " << quantity<arcminute_plane_angle>(d) << std::endl
                  << rev << " = " << quantity<arcminute_plane_angle>(rev) << std::endl
                  << std::endl;

        std::cout << as << " = " << quantity<degree_plane_angle>(as) << std::endl
                  << am << " = " << quantity<degree_plane_angle>(am) << std::endl
                  << d << " = " << quantity<degree_plane_angle>(d) << std::endl
                  << rev << " = " << quantity<degree_plane_angle>(rev) << std::endl
                  << std::endl;

        std::cout << as << " = " << quantity<revolution_plane_angle>(as) << std::endl
                  << am << " = " << quantity<revolution_plane_angle>(am) << std::endl
                  << d << " = " << quantity<revolution_plane_angle>(d) << std::endl
                  << rev << " = " << quantity<revolution_plane_angle>(rev) << std::endl
                  << std::endl;

        quantity<steradian_solid_angle>        sa1(1.0*steradians);

        std::cout << sa1 << std::endl
                  << std::endl;
    }

    {
        using namespace boost::units::astronomical;

        std::cout << "Testing astronomical base units..." << std::endl;

        quantity<light_second_length>        ls(1.0*light_seconds);
        quantity<light_minute_length>        lm(1.0*light_minutes);
        quantity<astronomical_unit_length>    au(1.0*astronomical_units);
        quantity<light_hour_length>            lh(1.0*light_hours);
        quantity<light_day_length>            ld(1.0*light_days);
        quantity<light_year_length>            ly(1.0*light_years);
        quantity<parsec_length>                ps(1.0*parsecs);

        std::cout << ls << " = " << quantity<si::length>(ls) << std::endl
                  << lm << " = " << quantity<si::length>(lm) << std::endl
                  << au << " = " << quantity<si::length>(au) << std::endl
                  << lh << " = " << quantity<si::length>(lh) << std::endl
                  << ld << " = " << quantity<si::length>(ld) << std::endl
                  << ly << " = " << quantity<si::length>(ly) << std::endl
                  << ps << " = " << quantity<si::length>(ps) << std::endl
                  << std::endl;

        std::cout << ly << "/" << ls << " = " << quantity<si::dimensionless>(ly/ls) << std::endl
                  << ly << "/" << lm << " = " << quantity<si::dimensionless>(ly/lm) << std::endl
                  << ly << "/" << au << " = " << quantity<si::dimensionless>(ly/au) << std::endl
                  << ly << "/" << lh << " = " << quantity<si::dimensionless>(ly/ld) << std::endl
                  << ly << "/" << ld << " = " << quantity<si::dimensionless>(ly/lh) << std::endl
                  << ly << "/" << ps << " = " << quantity<si::dimensionless>(ly/ps) << std::endl
                  << std::endl;

        std::cout << ls << " = " << quantity<light_second_length>(ls) << std::endl
                  << lm << " = " << quantity<light_second_length>(lm) << std::endl
                  << lh << " = " << quantity<light_second_length>(lh) << std::endl
                  << ld << " = " << quantity<light_second_length>(ld) << std::endl
                  << ly << " = " << quantity<light_second_length>(ly) << std::endl
                  << std::endl;

        std::cout << ls << " = " << quantity<light_minute_length>(ls) << std::endl
                  << lm << " = " << quantity<light_minute_length>(lm) << std::endl
                  << lh << " = " << quantity<light_minute_length>(lh) << std::endl
                  << ld << " = " << quantity<light_minute_length>(ld) << std::endl
                  << ly << " = " << quantity<light_minute_length>(ly) << std::endl
                  << std::endl;

        std::cout << ls << " = " << quantity<light_hour_length>(ls) << std::endl
                  << lm << " = " << quantity<light_hour_length>(lm) << std::endl
                  << lh << " = " << quantity<light_hour_length>(lh) << std::endl
                  << ld << " = " << quantity<light_hour_length>(ld) << std::endl
                  << ly << " = " << quantity<light_hour_length>(ly) << std::endl
                  << std::endl;

        std::cout << ls << " = " << quantity<light_day_length>(ls) << std::endl
                  << lm << " = " << quantity<light_day_length>(lm) << std::endl
                  << lh << " = " << quantity<light_day_length>(lh) << std::endl
                  << ld << " = " << quantity<light_day_length>(ld) << std::endl
                  << ly << " = " << quantity<light_day_length>(ly) << std::endl
                  << std::endl;

        std::cout << ls << " = " << quantity<light_year_length>(ls) << std::endl
                  << lm << " = " << quantity<light_year_length>(lm) << std::endl
                  << lh << " = " << quantity<light_year_length>(ld) << std::endl
                  << ld << " = " << quantity<light_year_length>(lh) << std::endl
                  << ly << " = " << quantity<light_year_length>(ly) << std::endl
                  << std::endl;
    }

    {
        using namespace boost::units::imperial;

        std::cout << "Testing imperial base units..." << std::endl;

        quantity<thou_length>            iml1(1.0*thous);
        quantity<inch_length>            iml2(1.0*inchs);
        quantity<foot_length>            iml3(1.0*foots);
        quantity<yard_length>            iml4(1.0*yards);
        quantity<furlong_length>        iml5(1.0*furlongs);
        quantity<mile_length>            iml6(1.0*miles);
        quantity<league_length>            iml7(1.0*leagues);

        std::cout << iml1 << " = " << quantity<si::length>(iml1) << std::endl
                  << iml2 << " = " << quantity<si::length>(iml2) << std::endl
                  << iml3 << " = " << quantity<si::length>(iml3) << std::endl
                  << iml4 << " = " << quantity<si::length>(iml4) << std::endl
                  << iml5 << " = " << quantity<si::length>(iml5) << std::endl
                  << iml6 << " = " << quantity<si::length>(iml6) << std::endl
                  << iml7 << " = " << quantity<si::length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml7 << "/" << iml1 << " = " << quantity<si::dimensionless>(iml7/iml1) << std::endl
                  << iml7 << "/" << iml2 << " = " << quantity<si::dimensionless>(iml7/iml2) << std::endl
                  << iml7 << "/" << iml3 << " = " << quantity<si::dimensionless>(iml7/iml3) << std::endl
                  << iml7 << "/" << iml4 << " = " << quantity<si::dimensionless>(iml7/iml4) << std::endl
                  << iml7 << "/" << iml5 << " = " << quantity<si::dimensionless>(iml7/iml5) << std::endl
                  << iml7 << "/" << iml6 << " = " << quantity<si::dimensionless>(iml7/iml6) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<thou_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<thou_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<thou_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<thou_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<thou_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<thou_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<thou_length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<inch_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<inch_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<inch_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<inch_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<inch_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<inch_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<inch_length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<foot_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<foot_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<foot_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<foot_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<foot_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<foot_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<foot_length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<yard_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<yard_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<yard_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<yard_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<yard_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<yard_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<yard_length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<furlong_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<furlong_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<furlong_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<furlong_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<furlong_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<furlong_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<furlong_length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<mile_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<mile_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<mile_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<mile_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<mile_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<mile_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<mile_length>(iml7) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<league_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<league_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<league_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<league_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<league_length>(iml5) << std::endl
                  << iml6 << " = " << quantity<league_length>(iml6) << std::endl
                  << iml7 << " = " << quantity<league_length>(iml7) << std::endl
                  << std::endl;

        quantity<grain_mass>            imm1(1.0*grains);
        quantity<drachm_mass>            imm2(1.0*drachms);
        quantity<ounce_mass>            imm3(1.0*ounces);
        quantity<pound_mass>            imm4(1.0*pounds);
        quantity<stone_mass>            imm5(1.0*stones);
        quantity<quarter_mass>            imm6(1.0*quarters);
        quantity<hundredweight_mass>    imm7(1.0*hundredweights);
        quantity<ton_mass>                imm8(1.0*tons);

        std::cout << imm1 << " = " << quantity<si::mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<si::mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<si::mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<si::mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<si::mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<si::mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<si::mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<si::mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm8 << "/" << imm1 << " = " << quantity<si::dimensionless>(imm8/imm1) << std::endl
                  << imm8 << "/" << imm2 << " = " << quantity<si::dimensionless>(imm8/imm2) << std::endl
                  << imm8 << "/" << imm3 << " = " << quantity<si::dimensionless>(imm8/imm3) << std::endl
                  << imm8 << "/" << imm4 << " = " << quantity<si::dimensionless>(imm8/imm4) << std::endl
                  << imm8 << "/" << imm5 << " = " << quantity<si::dimensionless>(imm8/imm5) << std::endl
                  << imm8 << "/" << imm6 << " = " << quantity<si::dimensionless>(imm8/imm6) << std::endl
                  << imm8 << "/" << imm7 << " = " << quantity<si::dimensionless>(imm8/imm7) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<grain_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<grain_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<grain_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<grain_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<grain_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<grain_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<grain_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<grain_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<drachm_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<drachm_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<drachm_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<drachm_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<drachm_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<drachm_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<drachm_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<drachm_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<ounce_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<ounce_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<ounce_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<ounce_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<ounce_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<ounce_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<ounce_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<ounce_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<pound_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<pound_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<pound_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<pound_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<pound_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<pound_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<pound_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<pound_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<stone_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<stone_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<stone_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<stone_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<stone_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<stone_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<stone_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<stone_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<quarter_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<quarter_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<quarter_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<quarter_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<quarter_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<quarter_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<quarter_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<quarter_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<hundredweight_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<hundredweight_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<hundredweight_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<hundredweight_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<hundredweight_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<hundredweight_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<hundredweight_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<hundredweight_mass>(imm8) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<ton_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<ton_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<ton_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<ton_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<ton_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<ton_mass>(imm6) << std::endl
                  << imm7 << " = " << quantity<ton_mass>(imm7) << std::endl
                  << imm8 << " = " << quantity<ton_mass>(imm8) << std::endl
                  << std::endl;

        quantity<fluid_ounce_volume>    imv1(1.0*fluid_ounces);
        quantity<gill_volume>            imv2(1.0*gills);
        quantity<pint_volume>            imv3(1.0*pints);
        quantity<quart_volume>            imv4(1.0*quarts);
        quantity<gallon_volume>            imv5(1.0*gallons);

        std::cout << imv1 << " = " << quantity<si::volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<si::volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<si::volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<si::volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<si::volume>(imv5) << std::endl
                  << std::endl;

        std::cout << imv5 << "/" << imv1 << " = " << quantity<si::dimensionless>(imv5/imv1) << std::endl
                  << imv5 << "/" << imv2 << " = " << quantity<si::dimensionless>(imv5/imv2) << std::endl
                  << imv5 << "/" << imv3 << " = " << quantity<si::dimensionless>(imv5/imv3) << std::endl
                  << imv5 << "/" << imv4 << " = " << quantity<si::dimensionless>(imv5/imv4) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<fluid_ounce_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<fluid_ounce_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<fluid_ounce_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<fluid_ounce_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<fluid_ounce_volume>(imv5) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<gill_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<gill_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<gill_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<gill_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<gill_volume>(imv5) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<pint_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<pint_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<pint_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<pint_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<pint_volume>(imv5) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<quart_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<quart_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<quart_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<quart_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<quart_volume>(imv5) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<gallon_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<gallon_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<gallon_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<gallon_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<gallon_volume>(imv5) << std::endl
                  << std::endl;
    }

    {
        using namespace boost::units::metric;

        std::cout << "Testing metric base units..." << std::endl;

        quantity<fermi_length>            ml1(1.0*fermis);
        quantity<angstrom_length>        ml2(1.0*angstroms);
        quantity<micron_length>            ml3(1.0*microns);
        quantity<nautical_mile_length>    ml4(1.0*nautical_miles);

        std::cout << ml1 << " = " << quantity<si::length>(ml1) << std::endl
                  << ml2 << " = " << quantity<si::length>(ml2) << std::endl
                  << ml3 << " = " << quantity<si::length>(ml3) << std::endl
                  << ml4 << " = " << quantity<si::length>(ml4) << std::endl
                  << std::endl;

        std::cout << ml4 << "/" << ml1 << " = " << quantity<si::dimensionless>(ml4/ml1) << std::endl
                  << ml4 << "/" << ml2 << " = " << quantity<si::dimensionless>(ml4/ml2) << std::endl
                  << ml4 << "/" << ml3 << " = " << quantity<si::dimensionless>(ml4/ml3) << std::endl
                  << std::endl;

        std::cout << ml1 << " = " << quantity<fermi_length>(ml1) << std::endl
                  << ml2 << " = " << quantity<fermi_length>(ml2) << std::endl
                  << ml3 << " = " << quantity<fermi_length>(ml3) << std::endl
                  << ml4 << " = " << quantity<fermi_length>(ml4) << std::endl
                  << std::endl;

        std::cout << ml1 << " = " << quantity<angstrom_length>(ml1) << std::endl
                  << ml2 << " = " << quantity<angstrom_length>(ml2) << std::endl
                  << ml3 << " = " << quantity<angstrom_length>(ml3) << std::endl
                  << ml4 << " = " << quantity<angstrom_length>(ml4) << std::endl
                  << std::endl;

        std::cout << ml1 << " = " << quantity<micron_length>(ml1) << std::endl
                  << ml2 << " = " << quantity<micron_length>(ml2) << std::endl
                  << ml3 << " = " << quantity<micron_length>(ml3) << std::endl
                  << ml4 << " = " << quantity<micron_length>(ml4) << std::endl
                  << std::endl;

        std::cout << ml1 << " = " << quantity<nautical_mile_length>(ml1) << std::endl
                  << ml2 << " = " << quantity<nautical_mile_length>(ml2) << std::endl
                  << ml3 << " = " << quantity<nautical_mile_length>(ml3) << std::endl
                  << ml4 << " = " << quantity<nautical_mile_length>(ml4) << std::endl
                  << std::endl;

        quantity<ton_mass>    mm1(1.0*tons);

        std::cout << mm1 << " = " << quantity<cgs::mass>(mm1) << std::endl
                  //<< quantity<si::mass>(mm1) << std::endl    // this should work...
                  << std::endl;

        quantity<minute_time>    mt1(1.0*minutes);
        quantity<hour_time>        mt2(1.0*hours);
        quantity<day_time>        mt3(1.0*days);
        quantity<year_time>        mt4(1.0*years);

        std::cout << mt1 << " = " << quantity<si::time>(mt1) << std::endl
                  << mt2 << " = " << quantity<si::time>(mt2) << std::endl
                  << mt3 << " = " << quantity<si::time>(mt3) << std::endl
                  << mt4 << " = " << quantity<si::time>(mt4) << std::endl
                  << std::endl;

        std::cout << mt4 << "/" << mt1 << " = " << quantity<si::dimensionless>(mt4/mt1) << std::endl
                  << mt4 << "/" << mt2 << " = " << quantity<si::dimensionless>(mt4/mt2) << std::endl
                  << mt4 << "/" << mt3 << " = " << quantity<si::dimensionless>(mt4/mt3) << std::endl
                  << std::endl;

        std::cout << mt1 << " = " << quantity<minute_time>(mt1) << std::endl
                  << mt2 << " = " << quantity<minute_time>(mt2) << std::endl
                  << mt3 << " = " << quantity<minute_time>(mt3) << std::endl
                  << mt4 << " = " << quantity<minute_time>(mt4) << std::endl
                  << std::endl;

        std::cout << mt1 << " = " << quantity<hour_time>(mt1) << std::endl
                  << mt2 << " = " << quantity<hour_time>(mt2) << std::endl
                  << mt3 << " = " << quantity<hour_time>(mt3) << std::endl
                  << mt4 << " = " << quantity<hour_time>(mt4) << std::endl
                  << std::endl;

        std::cout << mt1 << " = " << quantity<day_time>(mt1) << std::endl
                  << mt2 << " = " << quantity<day_time>(mt2) << std::endl
                  << mt3 << " = " << quantity<day_time>(mt3) << std::endl
                  << mt4 << " = " << quantity<day_time>(mt4) << std::endl
                  << std::endl;

        std::cout << mt1 << " = " << quantity<year_time>(mt1) << std::endl
                  << mt2 << " = " << quantity<year_time>(mt2) << std::endl
                  << mt3 << " = " << quantity<year_time>(mt3) << std::endl
                  << mt4 << " = " << quantity<year_time>(mt4) << std::endl
                  << std::endl;

        quantity<knot_velocity>    ms1(1.0*knots);

        std::cout << ms1 << " = " << quantity<si::velocity>(ms1) << std::endl
                  << std::endl;

        quantity<barn_area>        ma1(1.0*barns);
        quantity<are_area>        ma2(1.0*ares);
        quantity<hectare_area>    ma3(1.0*hectares);

        std::cout << ma1 << " = " << quantity<si::area>(ma1) << std::endl
                  << ma2 << " = " << quantity<si::area>(ma2) << std::endl
                  << ma3 << " = " << quantity<si::area>(ma3) << std::endl
                  << std::endl;

        std::cout << ma3 << "/" << ma1 << " = " << quantity<si::dimensionless>(ma3/ma1) << std::endl
                  << ma3 << "/" << ma2 << " = " << quantity<si::dimensionless>(ma3/ma2) << std::endl
                  << std::endl;

        std::cout << ma1 << " = " << quantity<barn_area>(ma1) << std::endl
                  << ma2 << " = " << quantity<barn_area>(ma2) << std::endl
                  << ma3 << " = " << quantity<barn_area>(ma3) << std::endl
                  << std::endl;

        std::cout << ma1 << " = " << quantity<are_area>(ma1) << std::endl
                  << ma2 << " = " << quantity<are_area>(ma2) << std::endl
                  << ma3 << " = " << quantity<are_area>(ma3) << std::endl
                  << std::endl;

        std::cout << ma1 << " = " << quantity<hectare_area>(ma1) << std::endl
                  << ma2 << " = " << quantity<hectare_area>(ma2) << std::endl
                  << ma3 << " = " << quantity<hectare_area>(ma3) << std::endl
                  << std::endl;

        quantity<liter_volume>    mv1(1.0*liters);

        std::cout << mv1 << " = " << quantity<si::volume>(mv1) << std::endl
                  << std::endl;

        quantity<mmHg_pressure>            mp1(1.0*mmHgs);
        quantity<torr_pressure>            mp2(1.0*torrs);
        quantity<bar_pressure>            mp3(1.0*bars);
        quantity<atmosphere_pressure>    mp4(1.0*atmospheres);

        std::cout << mp1 << " = " << quantity<si::pressure>(mp1) << std::endl
                  << mp2 << " = " << quantity<si::pressure>(mp2) << std::endl
                  << mp3 << " = " << quantity<si::pressure>(mp3) << std::endl
                  << mp4 << " = " << quantity<si::pressure>(mp4) << std::endl
                  << std::endl;

        std::cout << mp4 << "/" << mp1 << " = " << quantity<si::dimensionless>(mp4/mp1) << std::endl
                  << mp4 << "/" << mp2  << " = " << quantity<si::dimensionless>(mp4/mp2) << std::endl
                  << mp4 << "/" << mp3  << " = " << quantity<si::dimensionless>(mp4/mp3) << std::endl
                  << std::endl;

        std::cout << mp1 << " = " << quantity<mmHg_pressure>(mp1) << std::endl
                  << mp2 << " = " << quantity<mmHg_pressure>(mp2) << std::endl
                  << mp3 << " = " << quantity<mmHg_pressure>(mp3) << std::endl
                  << mp4 << " = " << quantity<mmHg_pressure>(mp4) << std::endl
                  << std::endl;

        std::cout << mp1 << " = " << quantity<torr_pressure>(mp1) << std::endl
                  << mp2 << " = " << quantity<torr_pressure>(mp2) << std::endl
                  << mp3 << " = " << quantity<torr_pressure>(mp3) << std::endl
                  << mp4 << " = " << quantity<torr_pressure>(mp4) << std::endl
                  << std::endl;

        std::cout << mp1 << " = " << quantity<bar_pressure>(mp1) << std::endl
                  << mp2 << " = " << quantity<bar_pressure>(mp2) << std::endl
                  << mp3 << " = " << quantity<bar_pressure>(mp3) << std::endl
                  << mp4 << " = " << quantity<bar_pressure>(mp4) << std::endl
                  << std::endl;

        std::cout << mp1 << " = " << quantity<atmosphere_pressure>(mp1) << std::endl
                  << mp2 << " = " << quantity<atmosphere_pressure>(mp2) << std::endl
                  << mp3 << " = " << quantity<atmosphere_pressure>(mp3) << std::endl
                  << mp4 << " = " << quantity<atmosphere_pressure>(mp4) << std::endl
                  << std::endl;
    }

    {
        using namespace boost::units::us;

        std::cout << "Testing U.S. customary base units..." << std::endl;

        quantity<mil_length>            iml1(1.0*mils);
        quantity<inch_length>            iml2(1.0*inchs);
        quantity<foot_length>            iml3(1.0*foots);
        quantity<yard_length>            iml4(1.0*yards);
        quantity<mile_length>            iml5(1.0*miles);

        std::cout << iml1 << " = " << quantity<si::length>(iml1) << std::endl
                  << iml2 << " = " << quantity<si::length>(iml2) << std::endl
                  << iml3 << " = " << quantity<si::length>(iml3) << std::endl
                  << iml4 << " = " << quantity<si::length>(iml4) << std::endl
                  << iml5 << " = " << quantity<si::length>(iml5) << std::endl
                  << std::endl;

        std::cout << iml5 << "/" << iml1 << " = " << quantity<si::dimensionless>(iml5/iml1) << std::endl
                  << iml5 << "/" << iml2 << " = " << quantity<si::dimensionless>(iml5/iml2) << std::endl
                  << iml5 << "/" << iml3 << " = " << quantity<si::dimensionless>(iml5/iml3) << std::endl
                  << iml5 << "/" << iml4 << " = " << quantity<si::dimensionless>(iml5/iml4) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<mil_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<mil_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<mil_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<mil_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<mil_length>(iml5) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<inch_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<inch_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<inch_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<inch_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<inch_length>(iml5) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<foot_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<foot_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<foot_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<foot_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<foot_length>(iml5) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<yard_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<yard_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<yard_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<yard_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<yard_length>(iml5) << std::endl
                  << std::endl;

        std::cout << iml1 << " = " << quantity<mile_length>(iml1) << std::endl
                  << iml2 << " = " << quantity<mile_length>(iml2) << std::endl
                  << iml3 << " = " << quantity<mile_length>(iml3) << std::endl
                  << iml4 << " = " << quantity<mile_length>(iml4) << std::endl
                  << iml5 << " = " << quantity<mile_length>(iml5) << std::endl
                  << std::endl;

        quantity<grain_mass>            imm1(1.0*grains);
        quantity<dram_mass>                imm2(1.0*drams);
        quantity<ounce_mass>            imm3(1.0*ounces);
        quantity<pound_mass>            imm4(1.0*pounds);
        quantity<hundredweight_mass>    imm5(1.0*hundredweights);
        quantity<ton_mass>                imm6(1.0*tons);

        std::cout << imm1 << " = " << quantity<si::mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<si::mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<si::mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<si::mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<si::mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<si::mass>(imm6) << std::endl
                  << std::endl;

        std::cout << imm6 << "/" << imm1 << " = " << quantity<si::dimensionless>(imm6/imm1) << std::endl
                  << imm6 << "/" << imm2 << " = " << quantity<si::dimensionless>(imm6/imm2) << std::endl
                  << imm6 << "/" << imm3 << " = " << quantity<si::dimensionless>(imm6/imm3) << std::endl
                  << imm6 << "/" << imm4 << " = " << quantity<si::dimensionless>(imm6/imm4) << std::endl
                  << imm6 << "/" << imm5 << " = " << quantity<si::dimensionless>(imm6/imm5) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<grain_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<grain_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<grain_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<grain_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<grain_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<grain_mass>(imm6) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<dram_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<dram_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<dram_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<dram_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<dram_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<dram_mass>(imm6) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<ounce_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<ounce_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<ounce_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<ounce_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<ounce_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<ounce_mass>(imm6) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<pound_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<pound_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<pound_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<pound_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<pound_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<pound_mass>(imm6) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<hundredweight_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<hundredweight_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<hundredweight_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<hundredweight_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<hundredweight_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<hundredweight_mass>(imm6) << std::endl
                  << std::endl;

        std::cout << imm1 << " = " << quantity<ton_mass>(imm1) << std::endl
                  << imm2 << " = " << quantity<ton_mass>(imm2) << std::endl
                  << imm3 << " = " << quantity<ton_mass>(imm3) << std::endl
                  << imm4 << " = " << quantity<ton_mass>(imm4) << std::endl
                  << imm5 << " = " << quantity<ton_mass>(imm5) << std::endl
                  << imm6 << " = " << quantity<ton_mass>(imm6) << std::endl
                  << std::endl;

        quantity<minim_volume>            imv1(1.0*minims);
        quantity<fluid_dram_volume>        imv2(1.0*fluid_drams);
        quantity<teaspoon_volume>        imv3(1.0*teaspoons);
        quantity<tablespoon_volume>        imv4(1.0*tablespoons);
        quantity<fluid_ounce_volume>    imv5(1.0*fluid_ounces);
        quantity<gill_volume>            imv6(1.0*gills);
        quantity<cup_volume>            imv7(1.0*cups);
        quantity<pint_volume>            imv8(1.0*pints);
        quantity<quart_volume>            imv9(1.0*quarts);
        quantity<gallon_volume>            imv10(1.0*gallons);

        std::cout << imv1 << " = " << quantity<si::volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<si::volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<si::volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<si::volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<si::volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<si::volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<si::volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<si::volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<si::volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<si::volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv10 << "/" << imv1 << " = " << quantity<si::dimensionless>(imv10/imv1) << std::endl
                  << imv10 << "/" << imv2 << " = " << quantity<si::dimensionless>(imv10/imv2) << std::endl
                  << imv10 << "/" << imv3 << " = " << quantity<si::dimensionless>(imv10/imv3) << std::endl
                  << imv10 << "/" << imv4 << " = " << quantity<si::dimensionless>(imv10/imv4) << std::endl
                  << imv10 << "/" << imv5 << " = " << quantity<si::dimensionless>(imv10/imv5) << std::endl
                  << imv10 << "/" << imv6 << " = " << quantity<si::dimensionless>(imv10/imv6) << std::endl
                  << imv10 << "/" << imv7 << " = " << quantity<si::dimensionless>(imv10/imv7) << std::endl
                  << imv10 << "/" << imv8 << " = " << quantity<si::dimensionless>(imv10/imv8) << std::endl
                  << imv10 << "/" << imv9 << " = " << quantity<si::dimensionless>(imv10/imv9) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<minim_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<minim_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<minim_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<minim_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<minim_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<minim_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<minim_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<minim_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<minim_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<minim_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<fluid_dram_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<fluid_dram_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<fluid_dram_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<fluid_dram_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<fluid_dram_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<fluid_dram_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<fluid_dram_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<fluid_dram_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<fluid_dram_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<fluid_dram_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<teaspoon_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<teaspoon_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<teaspoon_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<teaspoon_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<teaspoon_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<teaspoon_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<teaspoon_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<teaspoon_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<teaspoon_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<teaspoon_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<tablespoon_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<tablespoon_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<tablespoon_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<tablespoon_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<tablespoon_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<tablespoon_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<tablespoon_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<tablespoon_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<tablespoon_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<tablespoon_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<fluid_ounce_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<fluid_ounce_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<fluid_ounce_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<fluid_ounce_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<fluid_ounce_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<fluid_ounce_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<fluid_ounce_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<fluid_ounce_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<fluid_ounce_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<fluid_ounce_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<gill_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<gill_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<gill_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<gill_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<gill_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<gill_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<gill_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<gill_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<gill_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<gill_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<cup_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<cup_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<cup_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<cup_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<cup_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<cup_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<cup_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<cup_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<cup_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<cup_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<pint_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<pint_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<pint_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<pint_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<pint_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<pint_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<pint_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<pint_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<pint_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<pint_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<quart_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<quart_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<quart_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<quart_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<quart_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<quart_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<quart_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<quart_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<quart_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<quart_volume>(imv10) << std::endl
                  << std::endl;

        std::cout << imv1 << " = " << quantity<gallon_volume>(imv1) << std::endl
                  << imv2 << " = " << quantity<gallon_volume>(imv2) << std::endl
                  << imv3 << " = " << quantity<gallon_volume>(imv3) << std::endl
                  << imv4 << " = " << quantity<gallon_volume>(imv4) << std::endl
                  << imv5 << " = " << quantity<gallon_volume>(imv5) << std::endl
                  << imv6 << " = " << quantity<gallon_volume>(imv6) << std::endl
                  << imv7 << " = " << quantity<gallon_volume>(imv7) << std::endl
                  << imv8 << " = " << quantity<gallon_volume>(imv8) << std::endl
                  << imv9 << " = " << quantity<gallon_volume>(imv9) << std::endl
                  << imv10 << " = " << quantity<gallon_volume>(imv10) << std::endl
                  << std::endl;
    }

    return 0;
}

ext: cpp

max_stars_repo_name: randolphwong/mcsema

max_issues_repo_name: randolphwong/mcsema

max_forks_repo_name: randolphwong/mcsema


text:
#include "CorePch.h"
#include <rtp++/rfc2326/RtspMessage.h>
#include <limits>
#include <boost/regex.hpp>
#include <cpputil/Conversion.h>
#include <cpputil/FileUtil.h>
#include <rtp++/rfc2326/HeaderFields.h>
#include <rtp++/rfc2326/MessageBody.h>

namespace rtp_plus_plus
{
namespace rfc2326
{

boost::optional<RtspMessage> RtspMessage::create(const std::string& sMethodOrResponseCode,
                                                 const std::string& sRtspUriOrResponseDescription,
                                                 const std::string& sVersion)
{
  RtspMethod eMethod = stringToMethod(sMethodOrResponseCode);
  if (eMethod != UNKNOWN)
  {
    return boost::optional<RtspMessage>(RtspMessage(sMethodOrResponseCode, sRtspUriOrResponseDescription, sVersion));
  }
  else
  {
    // try response
    ResponseCode eCode = stringToResponseCode(sMethodOrResponseCode);
    std::string sResponse = responseCodeString(eCode);
    // round-about way of checking which could fail if string is wrong...
    if (sResponse == sRtspUriOrResponseDescription)
    {
      RtspMessage rtspMessage;
      rtspMessage.setResponse(eCode);
      return boost::optional<RtspMessage>(rtspMessage);
    }
  }
  return boost::optional<RtspMessage>();
}

RtspMessage::RtspMessage()
  :m_sVersion("1.0"),
    m_eType(RTSP_NOT_SET),
    m_eMethod(UNKNOWN),
    m_eCode(NOT_SET)
{

}

RtspMessage::RtspMessage (const std::string& sMethod, const std::string& sRtspUri,
                          const std::string& sRtspVersion)
  :m_sVersion(sRtspVersion),
    m_eType(RTSP_REQUEST),
    m_eMethod(stringToMethod(sMethod)),
    m_sRtspUri(sRtspUri),
    m_eCode(NOT_SET)
{

}

std::string RtspMessage::getCSeq() const
{
  //  extract CSeq and use in response
  boost::optional<std::string> CSeq = getHeaderField(CSEQ);
  // there's a bug in the wowza server
  if (!CSeq)
  {
    const std::string CSEQ_WOWZA("Cseq");
    CSeq = getHeaderField(CSEQ_WOWZA);
    if (CSeq)
    {
      LOG(WARNING) << "Bug in Wowza CSeq header casing!";
    }
  }
  return (CSeq) ? *CSeq : "";
}

std::string RtspMessage::getSession() const
{
  //  extract CSeq and use in response
  boost::optional<std::string> Session = getHeaderField(SESSION);
  return (Session) ? *Session : "";
}

boost::optional<std::string> RtspMessage::getHeaderField(const std::string& sName) const
{
  auto it = m_mHeaderMap.find(sName);
  if (it != m_mHeaderMap.end())
  {
    return boost::optional<std::string>(it->second);
  }
  return boost::optional<std::string>();
}

// changes the data structure to be a response
void RtspMessage::setResponse(ResponseCode eCode)
{
  m_eType = RTSP_RESPONSE;
  m_eCode = eCode;
}

boost::optional<RtspMessage> RtspMessage::parse(const std::string& sRtspMessage)
{
#define DEBUG_INCOMING_RTSP
#ifdef DEBUG_INCOMING_RTSP
  static int fileNo = 0;
  std::ostringstream outFile;
  outFile << "rtsp_" << fileNo++ << ".log";
  FileUtil::writeFile(outFile.str().c_str(), sRtspMessage, false);
#endif

  boost::regex rtspUri_regex("(OPTIONS|DESCRIBE|SETUP|PLAY|PAUSE|TEARDOWN|GET_PARAMETER|SET_PARAMETER|REGISTER) (rtsp://[^ ]+) RTSP/([0-9].[0-9])");

  std::istringstream istr(sRtspMessage);
  std::string sLine;
  if (std::getline(istr, sLine))
  {
    boost::smatch match;
    if (boost::regex_search(sLine, match, rtspUri_regex))
    {
      std::string sMethod = match[1];
      std::string sRtspUri = match[2];
      std::string sRtspVersion = match[3];
      VLOG(15) << "Match RTSP request. Version: " << sRtspVersion << " Method: " << sMethod << " URI: " << sRtspUri;
      RtspMessage rtspMessage(sMethod, sRtspUri, sRtspVersion);
      if (rtspMessage.getMethod() != UNKNOWN)
      {
        // read remaining header fields
        while (std::getline(istr, sLine))
        {
          size_t pos = sLine.find_first_of(':');
          if (pos == std::string::npos)
          {
            break;
          }
          std::string sValue = sLine.substr(pos + 1);
          boost::algorithm::trim(sValue);
          rtspMessage.m_mHeaderMap[sLine.substr(0, pos)] = sValue;
        }
        return boost::optional<RtspMessage>(rtspMessage);
      }
      else
      {
        LOG(WARNING) << "Unknown RTSP method: " << rtspMessage.getMethod();
        return boost::optional<RtspMessage>();
      }
    }
    else
    {
      VLOG(15) << "Didn't match request - trying to match response.";
      // try to match response header
      boost::regex rtspResponse_regex("RTSP/([0-9].[0-9]) ([0-9][0-9][0-9]) (\\w*)");
      //        if (boost::algorithm::starts_with(sLine, "RTSP/1.0 "))
      if (boost::regex_search(sLine, match, rtspResponse_regex))
      {
        std::string sResponseCode = match[2];
        std::string sResponseMessage = match[3];
        VLOG(10) << "Matched RTSP response. Code: " << sResponseCode << " Message: " << sResponseMessage;

        ResponseCode eCode = stringToResponseCode(sResponseCode);
        RtspMessage rtspMessage;
        rtspMessage.setResponse(eCode);

        // read remaining header fields
        while (std::getline(istr, sLine))
        {
          size_t pos = sLine.find_first_of(':');

          if (pos == std::string::npos)
          {
            std::ostringstream ostr;
            while (std::getline(istr, sLine))
            {
              ostr << sLine << "\n";
            }
            std::string sMessageBody = ostr.str();
            if (!sMessageBody.empty())
            {
              MessageBody messageBody(sMessageBody);
              rtspMessage.setMessageBody(messageBody);
            }
            break;
          }
          // assert(pos != std::string::npos);

          std::string sValue = sLine.substr(pos + 1);
          boost::algorithm::trim(sValue);
          rtspMessage.m_mHeaderMap[sLine.substr(0, pos)] = sValue;
        }

        return boost::optional<RtspMessage>(rtspMessage);
      }
      else
      {
        LOG(WARNING) << "Parsing RTSP: Failed to match request or response";
        return boost::optional<RtspMessage>();
      }
    }
  }
  else
  {
    LOG(WARNING) << "Parsing RTSP: Failed to getline";
    return boost::optional<RtspMessage>();
  }
}

} // rfc2326
} // rtp_plus_plus


text:
//Copyright (c) 2008-2016 Emil Dotchevski and Reverge Studios, Inc.

//Distributed under the Boost Software License, Version 1.0. (See accompanying

//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef UUID_10F2D1EA17B511E0BA29FE0BDFD72085

#define UUID_10F2D1EA17B511E0BA29FE0BDFD72085

#include <boost/qvm/vec_traits.hpp>

#include <boost/qvm/inline.hpp>

#include <boost/qvm/static_assert.hpp>

#include <boost/qvm/enable_if.hpp>

namespace

boost

    {

    namespace

    qvm

        {

        ////////////////////////////////////////////////

        template <int I,class V>

        BOOST_QVM_INLINE_TRIVIAL

        typename enable_if_c<

            is_vec<V>::value,

            typename vec_traits<V>::scalar_type>::type

        A( V const & a )

            {

            BOOST_STATIC_ASSERT(I>=0);

            BOOST_STATIC_ASSERT(I<vec_traits<V>::dim);

            return vec_traits<V>::template read_element<I>(a);

            }

        template <int I,class V>

        BOOST_QVM_INLINE_TRIVIAL

        typename enable_if_c<

            is_vec<V>::value,

            typename vec_traits<V>::scalar_type &>::type

        A( V & a )

            {

            BOOST_STATIC_ASSERT(I>=0);

            BOOST_STATIC_ASSERT(I<vec_traits<V>::dim);

            return vec_traits<V>::template write_element<I>(a);

            }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type X( V const & a ) { BOOST_STATIC_ASSERT(0<vec_traits<V>::dim); return vec_traits<V>::template read_element<0>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type Y( V const & a ) { BOOST_STATIC_ASSERT(1<vec_traits<V>::dim); return vec_traits<V>::template read_element<1>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type Z( V const & a ) { BOOST_STATIC_ASSERT(2<vec_traits<V>::dim); return vec_traits<V>::template read_element<2>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type W( V const & a ) { BOOST_STATIC_ASSERT(3<vec_traits<V>::dim); return vec_traits<V>::template read_element<3>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type X( V & a ) { BOOST_STATIC_ASSERT(0<vec_traits<V>::dim); return vec_traits<V>::template write_element<0>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type Y( V & a ) { BOOST_STATIC_ASSERT(1<vec_traits<V>::dim); return vec_traits<V>::template write_element<1>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type Z( V & a ) { BOOST_STATIC_ASSERT(2<vec_traits<V>::dim); return vec_traits<V>::template write_element<2>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type W( V & a ) { BOOST_STATIC_ASSERT(3<vec_traits<V>::dim); return vec_traits<V>::template write_element<3>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A0( V const & a ) { BOOST_STATIC_ASSERT(0<vec_traits<V>::dim); return vec_traits<V>::template read_element<0>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A1( V const & a ) { BOOST_STATIC_ASSERT(1<vec_traits<V>::dim); return vec_traits<V>::template read_element<1>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A2( V const & a ) { BOOST_STATIC_ASSERT(2<vec_traits<V>::dim); return vec_traits<V>::template read_element<2>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A3( V const & a ) { BOOST_STATIC_ASSERT(3<vec_traits<V>::dim); return vec_traits<V>::template read_element<3>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A4( V const & a ) { BOOST_STATIC_ASSERT(4<vec_traits<V>::dim); return vec_traits<V>::template read_element<4>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A5( V const & a ) { BOOST_STATIC_ASSERT(5<vec_traits<V>::dim); return vec_traits<V>::template read_element<5>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A6( V const & a ) { BOOST_STATIC_ASSERT(6<vec_traits<V>::dim); return vec_traits<V>::template read_element<6>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A7( V const & a ) { BOOST_STATIC_ASSERT(7<vec_traits<V>::dim); return vec_traits<V>::template read_element<7>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A8( V const & a ) { BOOST_STATIC_ASSERT(8<vec_traits<V>::dim); return vec_traits<V>::template read_element<8>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type>::type A9( V const & a ) { BOOST_STATIC_ASSERT(9<vec_traits<V>::dim); return vec_traits<V>::template read_element<9>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A0( V & a ) {  BOOST_STATIC_ASSERT(0<vec_traits<V>::dim); return vec_traits<V>::template write_element<0>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A1( V & a ) {  BOOST_STATIC_ASSERT(1<vec_traits<V>::dim); return vec_traits<V>::template write_element<1>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A2( V & a ) {  BOOST_STATIC_ASSERT(2<vec_traits<V>::dim); return vec_traits<V>::template write_element<2>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A3( V & a ) {  BOOST_STATIC_ASSERT(3<vec_traits<V>::dim); return vec_traits<V>::template write_element<3>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A4( V & a ) {  BOOST_STATIC_ASSERT(4<vec_traits<V>::dim); return vec_traits<V>::template write_element<4>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A5( V & a ) {  BOOST_STATIC_ASSERT(5<vec_traits<V>::dim); return vec_traits<V>::template write_element<5>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A6( V & a ) {  BOOST_STATIC_ASSERT(6<vec_traits<V>::dim); return vec_traits<V>::template write_element<6>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A7( V & a ) {  BOOST_STATIC_ASSERT(7<vec_traits<V>::dim); return vec_traits<V>::template write_element<7>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A8( V & a ) {  BOOST_STATIC_ASSERT(8<vec_traits<V>::dim); return vec_traits<V>::template write_element<8>(a); }

        template <class V> BOOST_QVM_INLINE_TRIVIAL typename enable_if_c<is_vec<V>::value,typename vec_traits<V>::scalar_type &>::type A9( V & a ) {  BOOST_STATIC_ASSERT(9<vec_traits<V>::dim); return vec_traits<V>::template write_element<9>(a); }

        ////////////////////////////////////////////////

        }

    }

#endif

ext: hpp

max_stars_repo_name: newtondev/drachtio-server

max_issues_repo_name: newtondev/drachtio-server

max_forks_repo_name: newtondev/drachtio-server


text:
/* vim:set ts=3 sw=3 sts=3 et: */
/**
 * Copyright © 2008-2013 Last.fm Limited
 *
 * This file is part of libmoost.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef MOOST_TRANSACTION_HANDLER_HPP__
#define MOOST_TRANSACTION_HANDLER_HPP__

// A very simple transaction handler, which queues jobs and attempts to commit
// them using a user defined commit functor. If this functor returns false or
// throws an exception the commit is deemed to have failed so the job is added
// back to the job queue and retried later.

// Tip: For a persisted queue take a look a moost/transaction/queue.hpp

#include <csignal>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>

namespace moost { namespace transaction {

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Async transaction handler
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// queueT has the following interface requirements:
//
//   Functions...
//      void push_back(value_type const &);
//      void pop_front();
//      value_type & front();
//      size_t size() const;
//      bool empty() const;
//
//   Typedefs...
//      value_type
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

template <
   typename queueT, // See above for interface requirements
   typename commitFunctorT
   >
class TransactionHandler : boost::noncopyable
{
public:
   TransactionHandler(queueT & queue, commitFunctorT commitFunctor) :
      m_sigRunning(0),m_queue(queue), m_commitFunctor(commitFunctor)
   {
      size_t qsize = m_queue.size();

      ///////////////////////////////////////////////////////////////////////////
      // Start transaction service
      m_spWork.reset(new boost::asio::io_service::work(m_ioService));
      m_spThread.reset(new boost::thread(boost::bind(&boost::asio::io_service::run, &m_ioService)));
      ///////////////////////////////////////////////////////////////////////////

      m_sigRunning = 1;

      // Post jobs for currently queued items
      postJob(qsize);
   }

   ~TransactionHandler()
   {
      // Stop backup service
      //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      // The service will try to flush all items in the queue and will requeue
      // any that fail; however, it will only try and flush what was in the queue
      // when it was signalled to stop, failed items put to the back of the queue
      // will not be retried, so they'll be lost unless queue is fully persisted.

      m_sigRunning = 0;
      m_spWork.reset();
      m_spThread->join();
   }

   typedef typename queueT::value_type value_type;

   void post(value_type const data)
   {
      // Add data item to the queue
      {
         unique_lock_t rl(m_mtx);
         m_queue.push_back(data);
      }

      postJob();
    }

private:
   void postJob(size_t postCnt = 1)
   {
      // Tell asio we have jobs to process as long as the service is running
      for(size_t post = 0 ; m_sigRunning && (post < postCnt) ; ++post)
      {
         m_ioService.post(
            boost::bind(&TransactionHandler<queueT, commitFunctorT>::CommitHandler, this)
         );
      }
   }

   void CommitHandler()
   {
      // TODO: Should this drain the queue? Currently it'll process one
      //       item at a time, relying on the number of asio posts to
      //       be in sync with the number of queued items. Would forcing
      //       the full queue to be processed each post be better? It does
      //       mean the remaining asio posts will be noops, potentially,
      //       but it also means the queue will get fully processed.
      bool bCommited = false;

      // Take a copy of the data item so we can unlock mutex asap
      value_type data;
      {
         read_lock_t l(m_mtx);
         data = m_queue.front();
      }

      try
      {
         // Attempt commit
         bCommited = m_commitFunctor(data);
      }
      catch(...) { }

      // If there was an issue during the commit requeue
      if(!bCommited) { post(data); }

      // Remove current item from the front
      {
         unique_lock_t rl(m_mtx);
         m_queue.pop_front();
      }
   }

private:
   std::sig_atomic_t volatile m_sigRunning;
   queueT & m_queue;
   commitFunctorT m_commitFunctor;

   boost::asio::io_service m_ioService;
   boost::shared_ptr<boost::asio::io_service::work> m_spWork;
   boost::shared_ptr<boost::thread> m_spThread;

   typedef boost::shared_lock<boost::shared_mutex> read_lock_t;
   typedef boost::upgrade_lock<boost::shared_mutex> upgrade_lock_t;
   typedef boost::upgrade_to_unique_lock<boost::shared_mutex> upgrade_to_unique_lock;
   typedef boost::unique_lock<boost::shared_mutex> unique_lock_t;
   boost::shared_mutex m_mtx;
};

//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

}}

#endif // MOOST_TRANSACTION_HANDLER_HPP__

max_stars_repo_name: lastfm/libmoost

max_issues_repo_name: lastfm/libmoost

max_forks_repo_name: lastfm/libmoost


text:
/********************************************************* {COPYRIGHT-TOP} ***
* Copyright 2016 IBM Corporation
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the MIT License
* which accompanies this distribution, and is available at
* http://opensource.org/licenses/MIT
********************************************************** {COPYRIGHT-END} **/

#include "StatsdStatsWriter.hpp"
#include "UdpSocket.hpp"

#include <algorithm>
#include <boost/asio/ip/host_name.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/locale.hpp>
#include <cmath>
#include <exception>

using namespace boost::asio::ip;
using boost::locale::conv::utf_to_utf;

extern "C" {

  /*
   * This function is called by the IBM Integration Bus runtime when it loads the LIL file.
   * It is expecting a CsiStatsWriter object to be created using csiCreateStatsWriter() and
   * returned. The CsiStatsWriter is registered after this function has been called.
   */
  CsiStatsWriter LilFactoryExportPrefix * LilFactoryExportSuffix bipGetStatsWriter() {
    try {
      StatsdStatsWriter* instance = new StatsdStatsWriter();
      return instance->writer();
    } catch (const std::exception& e) {
      return nullptr;
    }
  }

}

namespace {

  /*
   * This is the C callback for getAttributeName(); simply forward the call onto the C++ object.
   */
  CciSize getAttributeNameCallback(int* rc, int index, CciChar* buffer, CciSize bufferLength, void* context) {
    StatsdStatsWriter* writer = reinterpret_cast<StatsdStatsWriter*>(context);
    return writer->getAttributeName(rc, index, buffer, bufferLength);
  }

  /*
   * This is the C callback for getAttribute(); simply forward the call onto the C++ object.
   */
  CciSize getAttributeCallback(int* rc, const CciChar* name, CciChar* buffer, CciSize bufferLength, void* context) {
    StatsdStatsWriter* writer = reinterpret_cast<StatsdStatsWriter*>(context);
    return writer->getAttribute(rc, name, buffer, bufferLength);
  }

  /*
   * This is the C callback for setAttribute(); simply forward the call onto the C++ object.
   */
  void setAttributeCallback(int* rc, const CciChar* name, const CciChar* value, void* context) {
    StatsdStatsWriter* writer = reinterpret_cast<StatsdStatsWriter*>(context);
    writer->setAttribute(rc, name, value);
  }

  /*
   * This is the C callback for write(); simply forward the call onto the C++ object.
   */
  void writeCallback(const CsiStatsRecord* record, void* context) {
    StatsdStatsWriter* writer = reinterpret_cast<StatsdStatsWriter*>(context);
    writer->write(record);
  }

  /*
   * This is the name of the statistics writer resource. This is the name that should
   * be passed to the mqsichangeproperties or mqsireportproperties commands to change
   * or report on properties of this statistics writer, for example:
   *
   * mqsireportproperties NODE -e SERVER -o GettingStartedStatsWriter -r
   * mqsichangeproperties NODE -e SERVER -o GettingStartedStatsWriter -n property1,property2 -v value1,value2
   */
  const std::u16string RESOURCE_NAME(u"StatsdStatsWriter");

  /*
   * This is the name of the "format" written by this statistics writer. This is the
   * name that should be passed to mqsichangeflowstats command to enable writing
   * statistics using this statistics writer for a specific message flow or set of
   * message flows, for example:
   *
   * mqsichangeflowstats NODE -s -e SERVER -f FLOW -c active -o gettingstarted
   */
  const std::u16string FORMAT_NAME(u"statsd");

  /*
   * This is the name of a property of this statistics writer. The value of the
   * property can be accessed using the mqsichangeproperties or mqsireportproperties
   * commands (see above).
   */
  const std::u16string HOSTNAME_NAME(u"hostname");

  /*
   * This is the name of a property of this statistics writer. The value of the
   * property can be accessed using the mqsichangeproperties or mqsireportproperties
   * commands (see above).
   */
  const std::u16string PORT_NAME(u"port");

}

/*
 * Constructor.
 */
StatsdStatsWriter::StatsdStatsWriter(UdpSocket *socket)
 : iWriter(nullptr)
{
  /*
   * Set the socket initially to the passed-in socket if it has
   * been set; this is normally used for unit testing with a mock
   * socket.
   */
  if ( socket != NULL )
    iSocket.reset(socket);

  /*
   * Create the virtual function table for the statistics writer.
   * These functions will be called by the IBM Integration Bus
   * runtime when it needs to interact with the statistics writer.
   */
  CsiStatsWriterVft vft = { CSI_STATS_WRITER_VFT_DEFAULT };
  vft.getAttributeName = &getAttributeNameCallback;
  vft.getAttribute = &getAttributeCallback;
  vft.setAttribute = &setAttributeCallback;
  vft.write = &writeCallback;

  /*
   * Create the statistics writer, passing it the virtual function
   * table, resource name, and format name that are defined above.
   * If this function returns an error, then throw an exception so
   * that we will return nullptr as the result of the bipGetStatsWriter()
   * call.
   */
  int returnCode = CCI_FAILURE;
  iWriter = csiCreateStatsWriter(
    &returnCode,
    RESOURCE_NAME.c_str(),
    FORMAT_NAME.c_str(),
    &vft,
    this
  );
  if (returnCode != CCI_SUCCESS) {
    const char16_t* traceText = u"Call to csiCreateStatsWriter failed";
    const char16_t* inserts[] = { traceText, RESOURCE_NAME.c_str(), FORMAT_NAME.c_str() };
    cciLogWithInsertsW(nullptr, CCI_LOG_ERROR,__FILE__, __LINE__, __func__, u"BIPmsgs", 2113, traceText, inserts, sizeof(inserts) / sizeof(inserts[0]));
    throw std::exception();
  }

}

/*
 * Destructor.
 */
StatsdStatsWriter::~StatsdStatsWriter() {

}

/*
 * Called by the IBM Integration Bus runtime to get the name of the property at the
 * specified index. If no property exists at the specified index, then this function
 * should return CCI_ATTRIBUTE_UNKNOWN. If the specified buffer is too small for the
 * name of the property, then this function should return CCI_BUFFER_TOO_SMALL and
 * the required size of the buffer.
 */
CciSize StatsdStatsWriter::getAttributeName(int* rc, int index, CciChar* buffer, CciSize bufferLength) const {
  switch (index) {
  case 0:
    if (bufferLength < HOSTNAME_NAME.length()) {
      if (rc) *rc = CCI_BUFFER_TOO_SMALL;
      return HOSTNAME_NAME.length();
    }
    if (rc) *rc = CCI_SUCCESS;
    return HOSTNAME_NAME.copy(buffer, HOSTNAME_NAME.length());
  case 1:
    if (bufferLength < PORT_NAME.length()) {
      if (rc) *rc = CCI_BUFFER_TOO_SMALL;
      return PORT_NAME.length();
    }
    if (rc) *rc = CCI_SUCCESS;
    return PORT_NAME.copy(buffer, PORT_NAME.length());
  default:
    *rc = CCI_ATTRIBUTE_UNKNOWN;
    return 0;
  }
}

/*
 * Called by the IBM Integration Bus runtime to get the value of the property with the
 * specified name. If no property exists with the specified name, then this function
 * should return CCI_ATTRIBUTE_UNKNOWN. If the specified buffer is too small for the
 * value of the property, then this function should return CCI_BUFFER_TOO_SMALL and
 * the required size of the buffer.
 */
CciSize StatsdStatsWriter::getAttribute(int* rc, const CciChar* name, CciChar* buffer, CciSize bufferLength) const {
  if (HOSTNAME_NAME == name) {
    if (bufferLength < iHostname.length()) {
      if (rc) *rc = CCI_BUFFER_TOO_SMALL;
      return iHostname.length();
    }
    if (rc) *rc = CCI_SUCCESS;
    return iHostname.copy(buffer, iHostname.length());
  } else if (PORT_NAME == name) {
    if (bufferLength < iPort.length()) {
      if (rc) *rc = CCI_BUFFER_TOO_SMALL;
      return iPort.length();
    }
    if (rc) *rc = CCI_SUCCESS;
    return iPort.copy(buffer, iPort.length());
  } else {
    if (rc) *rc = CCI_ATTRIBUTE_UNKNOWN;
    return 0;
  }
}

/*
 * Called by the IBM Integration Bus runtime to set the value of the property with the
 * specified name. If no property exists with the specified name, then this function
 * should return CCI_ATTRIBUTE_UNKNOWN.
 */
void StatsdStatsWriter::setAttribute(int* rc, const CciChar* name, const CciChar* value) {
  if (HOSTNAME_NAME == name) {
    iHostname.assign(value);
    if (rc) *rc = CCI_SUCCESS;
  } else if (PORT_NAME == name) {
    iPort.assign(value);
    if (rc) *rc = CCI_SUCCESS;
  } else {
    if (rc) *rc = CCI_ATTRIBUTE_UNKNOWN;
  }
  if (!iHostname.empty() && !iPort.empty()) {
    iSocket.reset(new UdpSocket(iHostname, iPort));
  } else {
    iSocket.reset();
  }
}

/*
 * Called by the IBM Integration Bus runtime to write the specified statistics record.
 * The statistics record contains data for one message flow with statistics enabled, so
 * this function will be called once per message flow.
 */
void StatsdStatsWriter::write(const CsiStatsRecord* record) {

  /*
   * If not connected, or we haven't been configured, then bail out early.
   */
#if defined(AVOID_CXX11)
  if (iSocket.get() == NULL) { return; }
#else
    if (!iSocket) { return; }
#endif

  /*
   * Calculate the base name for all of the metrics. This is as follows:
   * hostname.nodename.servername.uniqueflowname
   */
  std::u16string hostname(utf_to_utf<char16_t>(host_name()));
  hostname = hostname.substr(0, hostname.find(u'.'));
  std::u16string nodename(record->messageFlow.brokerLabel);
  std::replace(nodename.begin(), nodename.end(), u'.', u'_');
  std::u16string servername(record->messageFlow.executionGroupName);
  std::replace(servername.begin(), servername.end(), u'.', u'_');
  std::u16string uniqueservername;
  uniqueservername += hostname + u'.';
  if (!nodename.empty()) {
    uniqueservername += nodename + u'.';
  }
  if (!servername.empty()) {
    uniqueservername += servername + u'.';
  }

  /*
   * The unique flow name is built from the application, library, and
   * message flow names.
   */
  std::u16string application(record->messageFlow.applicationName);
  std::replace(application.begin(), application.end(), u'.', u'_');
  std::u16string library(record->messageFlow.libraryName);
  std::replace(library.begin(), library.end(), u'.', u'_');
  std::u16string messageflow(record->messageFlow.messageFlowName);
  std::replace(messageflow.begin(), messageflow.end(), u'.', u'_');
  std::u16string uniqueflowname;
  if (!application.empty()) {
    uniqueflowname += application + u'.';
  }
  if (!library.empty()) {
    uniqueflowname += library + u'.';
  }
  uniqueflowname += messageflow;
  std::u16string metricbase = uniqueservername + uniqueflowname + u'.';

  /*
   * Calculate the time interval for this record.
   */
  uint64_t startMillis = calculateMillis(record->messageFlow.startDate, record->messageFlow.startTime);
  uint64_t endMillis = calculateMillis(record->messageFlow.endDate, record->messageFlow.endTime);
  uint64_t duration = endMillis - startMillis;

  /*
   * Generate and send all of the metrics.
   */
  writeMessageFlowMetrics(metricbase, record, duration);

  /*
   * Ensure that all data is written to the socket. The UdpSocket class will
   * package the metrics into as few UDP packets as possible.
   */
  iSocket->flush();

}

/*
 * Calculate the time in milliseconds since the epoch from the specified date and time.
 */
uint64_t StatsdStatsWriter::calculateMillis(const CciDate& date, const CciTime& time) {
  struct tm temp = { 0 };
  temp.tm_year = date.year;
  temp.tm_mon = date.month;
  temp.tm_mday = date.day;
  temp.tm_hour = time.hour;
  temp.tm_min = time.minute;
  double seconds;
  uint64_t millis = static_cast<uint64_t>(modf(time.second, &seconds) * 1000);
  temp.tm_sec = static_cast<int>(seconds);
  time_t epochtime = mktime(&temp);
  return (epochtime * 1000) + millis;
}

/*
 * Write all the message flow specific metrics from the specified statistics record.
 */
void StatsdStatsWriter::writeMessageFlowMetrics(const std::u16string& metricbase, const CsiStatsRecord* record, uint64_t duration) {

  /*
   * Minimum and maximum CPU time and elapsed time in seconds.
   */
  writeMetric(metricbase, u"minimumCPUTime", record->messageFlow.minimumCPUTime / 1000.0f);
  writeMetric(metricbase, u"maximumCPUTime", record->messageFlow.maximumCPUTime / 1000.0f);
  writeMetric(metricbase, u"minimumElapsedTime", record->messageFlow.minimumElapsedTime / 1000.0f);
  writeMetric(metricbase, u"maximumElapsedTime", record->messageFlow.maximumElapsedTime / 1000.0f);

  /*
   * Average message rate in messages/second.
   */
  double averageMessageRate = 0;
  if (record->messageFlow.totalInputMessages > 0) {
    averageMessageRate = record->messageFlow.totalInputMessages / (duration / 1000.0f);
  }
  writeMetric(metricbase, u"averageMessageRate", averageMessageRate);

  /*
   * Average CPU time per message in seconds.
   */
  double averageCPUTimePerMessage = 0;
  if (record->messageFlow.totalInputMessages > 0) {
    averageCPUTimePerMessage = (record->messageFlow.totalCPUTime / static_cast<double>(record->messageFlow.totalInputMessages)) / 1000.0f;
  }
  writeMetric(metricbase, u"averageCPUTimePerMessage", averageCPUTimePerMessage);

  /*
   * Average elapsed time per message in seconds.
   */
  double averageElapsedTimePerMessage = 0;
  if (record->messageFlow.totalInputMessages > 0) {
    averageElapsedTimePerMessage = (record->messageFlow.totalElapsedTime / static_cast<double>(record->messageFlow.totalInputMessages)) / 1000.0f;
  }
  writeMetric(metricbase, u"averageElapsedTimePerMessage", averageElapsedTimePerMessage);

}

/*
 * Write a single metric.
 */
template <class T>
void StatsdStatsWriter::writeMetric(const std::u16string& metricbase, const std::u16string& metricname, T value) {
  std::string metric(utf_to_utf<char>(metricbase) + utf_to_utf<char>(metricname));
  metric += ':';
  metric += std::to_string(value);
  metric += "|g";
  iSocket->send(metric);
}