<commit_before>/******************************************************************************
 * Copyright 2019 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/control/common/mrac_controller.h"

#include <iostream>
#include <string>

#include "cyber/common/file.h"
#include "gtest/gtest.h"
#include "modules/control/proto/control_conf.pb.h"
#include "modules/control/proto/mrac_conf.pb.h"

namespace apollo {
namespace control {

using Matrix = Eigen::MatrixXd;

class MracControllerTest : public ::testing::Test {
 public:
  virtual void SetUp() {
    std::string control_conf_file =
        "/apollo/modules/control/testdata/conf/control_conf.pb.txt";
    CHECK(cyber::common::GetProtoFromFile(control_conf_file, &control_conf_));
    lat_controller_conf_ = control_conf_.lat_controller_conf();
  }

 protected:
  ControlConf control_conf_;
  LatControllerConf lat_controller_conf_;
};

TEST_F(MracControllerTest, MracControl) {
  double dt = 0.01;
  Matrix state = Matrix::Zero(1, 1);
  MracConf mrac_conf = lat_controller_conf_.actuation_mrac_conf();
  MracController mrac_controller;
  mrac_controller.Init(mrac_conf, dt);
  mrac_controller.Reset();
  state(0, 0) = 6.0;
  EXPECT_NEAR(mrac_controller.Control(18.0, state, dt), 0.0, 1e-6);
  mrac_controller.Reset();
  state(0, 0) = 10.0;
  EXPECT_NEAR(mrac_controller.Control(18.0, state, dt), -8.48, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentReferenceState(), 6.0, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentStateAdaptionGain(), -0.2, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentInputAdaptionGain(), -0.36, 1e-6);
  EXPECT_NEAR(mrac_controller.Control(18.0, state, dt), -8.48, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentReferenceState(), 14.0, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentStateAdaptionGain(), -0.2, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentInputAdaptionGain(), -0.36, 1e-6);
  mrac_controller.Reset();
  state(0, 0) = -10.0;
  double control_value = mrac_controller.Control(-18.0, state, dt);
  EXPECT_NEAR(control_value, 8.48, 1e-6);
  dt = 0.0;
  EXPECT_EQ(mrac_controller.Control(-18.0, state, dt), control_value);
}

}  // namespace control
}  // namespace apollo
<commit_msg>Control: refactor the MRAC unit test to judge the Lyapunov PD conditions<commit_after>/******************************************************************************
 * Copyright 2019 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/control/common/mrac_controller.h"

#include <iostream>
#include <string>

#include "cyber/common/file.h"
#include "gtest/gtest.h"
#include "modules/control/proto/control_conf.pb.h"
#include "modules/control/proto/mrac_conf.pb.h"

namespace apollo {
namespace control {

using Matrix = Eigen::MatrixXd;

class MracControllerTest : public ::testing::Test {
 public:
  virtual void SetUp() {
    std::string control_conf_file =
        "/apollo/modules/control/testdata/conf/control_conf.pb.txt";
    CHECK(cyber::common::GetProtoFromFile(control_conf_file, &control_conf_));
    lat_controller_conf_ = control_conf_.lat_controller_conf();
  }

 protected:
  ControlConf control_conf_;
  LatControllerConf lat_controller_conf_;
};

// test the input-output of the model reference adaptive controller
TEST_F(MracControllerTest, MracControl) {
  double dt = 0.01;
  Matrix state = Matrix::Zero(1, 1);
  MracConf mrac_conf = lat_controller_conf_.actuation_mrac_conf();
  MracController mrac_controller;
  mrac_controller.Init(mrac_conf, dt);
  mrac_controller.Reset();
  state(0, 0) = 6.0;
  EXPECT_NEAR(mrac_controller.Control(18.0, state, dt), 0.0, 1e-6);
  mrac_controller.Reset();
  state(0, 0) = 10.0;
  EXPECT_NEAR(mrac_controller.Control(18.0, state, dt), -8.48, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentReferenceState(), 6.0, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentStateAdaptionGain(), -0.2, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentInputAdaptionGain(), -0.36, 1e-6);
  EXPECT_NEAR(mrac_controller.Control(18.0, state, dt), -8.48, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentReferenceState(), 14.0, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentStateAdaptionGain(), -0.2, 1e-6);
  EXPECT_NEAR(mrac_controller.CurrentInputAdaptionGain(), -0.36, 1e-6);
  mrac_controller.Reset();
  state(0, 0) = -10.0;
  double control_value = mrac_controller.Control(-18.0, state, dt);
  EXPECT_NEAR(control_value, 8.48, 1e-6);
  dt = 0.0;
  EXPECT_EQ(mrac_controller.Control(-18.0, state, dt), control_value);
}

// test the judgement of the symetric positive definite solution of the Lyapunov
// equation
TEST_F(MracControllerTest, CheckLyapunovPD) {
  double dt = 0.01;
  MracConf mrac_conf = lat_controller_conf_.actuation_mrac_conf();
  MracController mrac_controller;
  mrac_controller.Init(mrac_conf, dt);
  // test on 1st order adaption dynamics
  Matrix matrix_a = Matrix::Zero(1, 1);
  Matrix matrix_p = Matrix::Zero(1, 1);
  matrix_a(0, 0) = -100.0;
  matrix_p(0, 0) = 1.0;
  EXPECT_EQ(mrac_controller.CheckLyapunovPD(matrix_a, matrix_p), true);
  matrix_a(0, 0) = -100.0;
  matrix_p(0, 0) = -1.0;
  EXPECT_EQ(mrac_controller.CheckLyapunovPD(matrix_a, matrix_p), false);
  // test on 2nd order adaption dynamics
  matrix_a = Matrix::Zero(2, 2);
  matrix_p = Matrix::Zero(2, 2);
  matrix_a(0, 1) = 1.0;
  matrix_a(1, 0) = -100.0;
  matrix_a(1, 1) = -18.0;
  matrix_p(0, 0) = 1.0;
  matrix_p(1, 1) = 1.0;
  EXPECT_EQ(mrac_controller.CheckLyapunovPD(matrix_a, matrix_p), false);
  matrix_p(0, 0) = 1.0;
  matrix_p(1, 1) = 0.01;
  EXPECT_EQ(mrac_controller.CheckLyapunovPD(matrix_a, matrix_p), false);
  matrix_p(0, 0) = 10.0;
  matrix_p(0, 1) = 0.1;
  matrix_p(1, 0) = 0.1;
  matrix_p(1, 1) = 0.1;
  EXPECT_EQ(mrac_controller.CheckLyapunovPD(matrix_a, matrix_p), true);
}

}  // namespace control
}  // namespace apollo
<|endoftext|>


<commit_before>#line 2 "togo/traits.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file traits.hpp
@brief Type traits.
@ingroup utility
*/

#pragma once

#include <togo/config.hpp>

namespace togo {

/**
	@addtogroup utility
	@{
*/

/** @name Type traits */ /// @{

/// Type with static constexpr value equal to false.
struct false_type {
	static constexpr bool const value = false;
};

/// Type with static constexpr value equal to true.
struct true_type {
	static constexpr bool const value = true;
};

/** @cond INTERNAL */
namespace {
	template<bool, class>
	struct enable_if_impl;

	template<class T>
	struct enable_if_impl<false, T> {};

	template<class T>
	struct enable_if_impl<true, T> {
		using type = T;
	};
} // anonymous namespace
/** @endcond */ // INTERNAL

/// SFINAE enabler type alias.
template<bool C, class T = void>
using enable_if = typename enable_if_impl<C, T>::type;

/// @}

/// Enum-class bitwise operator enabler.
///
/// Specialize this class deriving from true_type to enable bit-wise
/// operators for an enum-class.
template<class>
struct enable_enum_bitwise_ops : false_type {};

/** @} */ // end of doc-group utility

} // namespace togo
<commit_msg>traits: added remove_ref and remove_cvr.<commit_after>#line 2 "togo/traits.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file traits.hpp
@brief Type traits.
@ingroup utility
*/

#pragma once

#include <togo/config.hpp>

namespace togo {

/**
	@addtogroup utility
	@{
*/

/** @name Type traits */ /// @{

/// Type with static constexpr value equal to false.
struct false_type {
	static constexpr bool const value = false;
};

/// Type with static constexpr value equal to true.
struct true_type {
	static constexpr bool const value = true;
};

/** @cond INTERNAL */
namespace {
	template<bool, class>
	struct enable_if_impl;

	template<class T>
	struct enable_if_impl<false, T> {};

	template<class T>
	struct enable_if_impl<true, T> {
		using type = T;
	};
} // anonymous namespace
/** @endcond */ // INTERNAL

/// SFINAE enabler type alias.
template<bool C, class T = void>
using enable_if = typename enable_if_impl<C, T>::type;

namespace {

template<class T>
struct remove_ref_impl {
	using type = T;
};

template<class T>
struct remove_ref_impl<T&> {
	using type = T;
};

} // anonymous namespace

/// Remove reference qualification from type.
template<class T>
using remove_ref = typename remove_ref_impl<T>::type;

namespace {

template<class T>
struct remove_cvr_impl {
	using type = T;
};

template<class T>
struct remove_cvr_impl<T const> {
	using type = T;
};

template<class T>
struct remove_cvr_impl<T volatile> {
	using type = T;
};

template<class T>
struct remove_cvr_impl<T const volatile> {
	using type = T;
};

} // anonymous namespace

/// Remove const, volatile, and reference qualifications from type.
template<class T>
using remove_cvr = typename remove_cvr_impl<remove_ref<T>>::type;

/// @}

/// Enum-class bitwise operator enabler.
///
/// Specialize this class deriving from true_type to enable bit-wise
/// operators for an enum-class.
template<class>
struct enable_enum_bitwise_ops : false_type {};

/** @} */ // end of doc-group utility

} // namespace togo
<|endoftext|>


<commit_before>#pragma once

/*
    Bitmask
    =======

    A generic implementation of the BitmaskType C++ concept
    http://en.cppreference.com/w/cpp/concept/BitmaskType

    Version: 1.1

    Latest version and documentation:
        https://github.com/oliora/bitmask

    Copyright (c) 2016-2017 Andrey Upadyshev (oliora@gmail.com)

    Distributed under the Boost Software License, Version 1.0.
    See http://www.boost.org/LICENSE_1_0.txt

    Changes history
    ---------------
    v1.1:
        - Change namespace from `boost` to `bitmask`
        - Add CMake package
          https://github.com/oliora/bitmask/issues/1
    v1.0:
        - Initial release
 */

#include <type_traits>
#include <functional>  // for std::hash
#include <limits>  // for std::numeric_limits
#include <cassert>

namespace bitmask_lib {

    namespace bitmask_detail {
        // Let's use std::void_t. It's introduced in C++17 but we can easily add it by ourself
        // See more at http://en.cppreference.com/w/cpp/types/void_t
        template<typename... Ts> struct make_void { typedef void type;};
        template<typename... Ts> using void_t = typename make_void<Ts...>::type;

        template<class T>
        struct underlying_type
        {
            static_assert(std::is_enum<T>::value, "T is not a enum type");

            using type = typename std::make_unsigned<typename std::underlying_type<T>::type>::type;
        };

        template<class T>
        using underlying_type_t = typename underlying_type<T>::type;

        template<class T, T MaxElement = T::_bitmask_max_element>
        struct mask_from_max_element
        {
            static constexpr underlying_type_t<T> max_element_value_ =
                static_cast<underlying_type_t<T>>(MaxElement);

            static_assert(max_element_value_ >= 0,
                          "Max element is negative");

            // If you really have to define a bitmask that uses the highest bit of signed type (i.e. the sign bit) then
            // define the value mask rather than the max element.
            static_assert(max_element_value_ <= (std::numeric_limits<typename std::underlying_type<T>::type>::max() >> 1) + 1,
                          "Max element is greater than the underlying type's highest bit");

            // `((value - 1) << 1) + 1` is used rather that simpler `(value << 1) - 1`
            // because latter overflows in case if `value` is the highest bit of the underlying type.
            static constexpr underlying_type_t<T> value =
                max_element_value_ ? ((max_element_value_ - 1) << 1) + 1 : 0;
        };

        template<class, class = void_t<>>
        struct has_max_element : std::false_type {};

        template<class T>
        struct has_max_element<T, void_t<decltype(T::_bitmask_max_element)>> : std::true_type {};

#if !defined _MSC_VER
        template<class, class = void_t<>>
        struct has_value_mask : std::false_type {};

        template<class T>
        struct has_value_mask<T, void_t<decltype(T::_bitmask_value_mask)>> : std::true_type {};
#else
        // MS Visual Studio 2015 (even Update 3) has weird support for expressions SFINAE
        // so I can't get a real check for `has_value_mask` to compile.
        template<class T>
        struct has_value_mask: std::integral_constant<bool, !has_max_element<T>::value> {};
#endif

        template<class T>
        struct is_valid_enum_definition : std::integral_constant<bool,
            !(has_value_mask<T>::value && has_max_element<T>::value)> {};

        template<class, class = void>
        struct enum_mask;

        template<class T>
        struct enum_mask<T, typename std::enable_if<has_max_element<T>::value>::type>
            : std::integral_constant<underlying_type_t<T>, mask_from_max_element<T>::value> {};

        template<class T>
        struct enum_mask<T, typename std::enable_if<has_value_mask<T>::value>::type>
            : std::integral_constant<underlying_type_t<T>, static_cast<underlying_type_t<T>>(T::_bitmask_value_mask)> {};

        template<class T>
        static constexpr underlying_type_t<T> disable_unused_function_warnings() noexcept
        {
            return (static_cast<T>(0) & static_cast<T>(0)).bits()
                & (static_cast<T>(0) | static_cast<T>(0)).bits()
                & (static_cast<T>(0) ^ static_cast<T>(0)).bits()
                & (~static_cast<T>(0)).bits()
                & bits(static_cast<T>(0));
        }

        template<class Assert>
        inline void constexpr_assert_failed(Assert&& a) noexcept { a(); }

        // When evaluated at compile time emits a compilation error if condition is not true.
        // Invokes the standard assert at run time.
        #define bitmask_constexpr_assert(cond) \
            ((void)((cond) ? 0 : (bitmask_lib::bitmask_detail::constexpr_assert_failed([](){ assert(!#cond);}), 0)))

        template<class T>
        inline constexpr T checked_value(T value, T mask)
        {
            return bitmask_constexpr_assert((value & ~mask) == 0), value;
        }
    }

    template<class T>
    inline constexpr bitmask_detail::underlying_type_t<T> get_enum_mask(const T&) noexcept
    {
        static_assert(bitmask_detail::is_valid_enum_definition<T>::value,
                      "Both of _bitmask_max_element and _bitmask_value_mask are specified");
        return bitmask_detail::enum_mask<T>::value;
    }

    template<class T>
    class bitmask
    {
    public:
        using value_type = T;
        using underlying_type = bitmask_detail::underlying_type_t<T>;

        static constexpr underlying_type mask_value = get_enum_mask(static_cast<value_type>(0));

        constexpr bitmask() noexcept = default;
        constexpr bitmask(std::nullptr_t) noexcept: m_bits{0} {}

        constexpr bitmask(value_type value) noexcept
        : m_bits{bitmask_detail::checked_value(static_cast<underlying_type>(value), mask_value)} {}

        constexpr underlying_type bits() const noexcept { return m_bits; }

        constexpr explicit operator bool() const noexcept { return bits() ? true : false; }

        constexpr bitmask operator ~ () const noexcept
        {
            return bitmask{std::true_type{}, ~m_bits & mask_value};
        }

        constexpr bitmask operator & (const bitmask& r) const noexcept
        {
            return bitmask{std::true_type{}, m_bits & r.m_bits};
        }

        constexpr bitmask operator | (const bitmask& r) const noexcept
        {
            return bitmask{std::true_type{}, m_bits | r.m_bits};
        }

        constexpr bitmask operator ^ (const bitmask& r) const noexcept
        {
            return bitmask{std::true_type{}, m_bits ^ r.m_bits};
        }

        bitmask& operator |= (const bitmask& r) noexcept
        {
            m_bits |= r.m_bits;
            return *this;
        }

        bitmask& operator &= (const bitmask& r) noexcept
        {
            m_bits &= r.m_bits;
            return *this;
        }

        bitmask& operator ^= (const bitmask& r) noexcept
        {
            m_bits ^= r.m_bits;
            return *this;
        }

    private:
        template<class U>
        constexpr bitmask(std::true_type, U bits) noexcept
        : m_bits(static_cast<underlying_type>(bits)) {}

        underlying_type m_bits = 0;
    };

    template<class T>
    inline constexpr bitmask<T>
    operator & (T l, const bitmask<T>& r) noexcept { return r & l; }

    template<class T>
    inline constexpr bitmask<T>
    operator | (T l, const bitmask<T>& r) noexcept { return r | l; }

    template<class T>
    inline constexpr bitmask<T>
    operator ^ (T l, const bitmask<T>& r) noexcept { return r ^ l; }

    template<class T>
    inline constexpr bool
    operator != (const bitmask<T>& l, const bitmask<T>& r) noexcept { return l.bits() != r.bits(); }

    template<class T>
    inline constexpr bool
    operator == (const bitmask<T>& l, const bitmask<T>& r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (T l, const bitmask<T>& r) noexcept { return static_cast<bitmask_detail::underlying_type_t<T>>(l) != r.bits(); }

    template<class T>
    inline constexpr bool
    operator == (T l, const bitmask<T>& r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (const bitmask<T>& l, T r) noexcept { return l.bits() != static_cast<bitmask_detail::underlying_type_t<T>>(r); }

    template<class T>
    inline constexpr bool operator == (const bitmask<T>& l, T r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (const bitmask_detail::underlying_type_t<T>& l, const bitmask<T>& r) noexcept { return l != r.bits(); }

    template<class T>
    inline constexpr bool
    operator == (const bitmask_detail::underlying_type_t<T>& l, const bitmask<T>& r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (const bitmask<T>& l, const bitmask_detail::underlying_type_t<T>& r) noexcept { return l.bits() != r; }

    template<class T>
    inline constexpr bool
    operator == (const bitmask<T>& l, const bitmask_detail::underlying_type_t<T>& r) noexcept { return ! operator != (l, r); }

    // Allow `bitmask` to be be used as a map key
    template<class T>
    inline constexpr bool
    operator < (const bitmask<T>& l, const bitmask<T>& r) noexcept { return l.bits() < r.bits(); }

    template<class T>
    inline constexpr bitmask_detail::underlying_type_t<T>
    bits(const bitmask<T>& bm) noexcept { return bm.bits(); }

    // Implementation

    template<class T>
    constexpr typename bitmask<T>::underlying_type bitmask<T>::mask_value;
}

namespace std
{
    template<class T>
    struct hash<bitmask_lib::bitmask<T>>
    {
        constexpr std::size_t operator() (const bitmask_lib::bitmask<T>& op) const noexcept
        {
            using ut = typename bitmask_lib::bitmask<T>::underlying_type;
            return std::hash<ut>{}(op.bits());
        }
    };
}

// Implementation detail macros

#define BITMASK_DETAIL_DEFINE_OPS(value_type) \
    inline constexpr bitmask_lib::bitmask<value_type> operator & (value_type l, value_type r) noexcept { return bitmask::bitmask<value_type>{l} & r; } \
    inline constexpr bitmask_lib::bitmask<value_type> operator | (value_type l, value_type r) noexcept { return bitmask::bitmask<value_type>{l} | r; } \
    inline constexpr bitmask_lib::bitmask<value_type> operator ^ (value_type l, value_type r) noexcept { return bitmask::bitmask<value_type>{l} ^ r; } \
    inline constexpr bitmask_lib::bitmask<value_type> operator ~ (value_type op) noexcept { return ~bitmask_lib::bitmask<value_type>{op}; }                \
    inline constexpr bitmask_lib::bitmask<value_type>::underlying_type bits(value_type op) noexcept { return bitmask_lib::bitmask<value_type>{op}.bits(); }\
    using unused_bitmask_ ## value_type ## _t_ = decltype(bitmask_lib::bitmask_detail::disable_unused_function_warnings<value_type>());

#define BITMASK_DETAIL_DEFINE_VALUE_MASK(value_type, value_mask) \
    inline constexpr bitmask_lib::bitmask_detail::underlying_type_t<value_type> get_enum_mask(value_type) noexcept { return value_mask; }

#define BITMASK_DETAIL_DEFINE_MAX_ELEMENT(value_type, max_element) \
    inline constexpr bitmask_lib::bitmask_detail::underlying_type_t<value_type> get_enum_mask(value_type) noexcept { \
        return bitmask_lib::bitmask_detail::mask_from_max_element<value_type, value_type::max_element>::value;       \
    }

// Public macros

// Defines missing operations for a bit-mask elements enum 'value_type'
// Value mask is taken from 'value_type' definition. One should has either
// '_bitmask_value_mask' or '_bitmask_max_element' element defined.
#define BITMASK_DEFINE(value_type) \
    BITMASK_DETAIL_DEFINE_OPS(value_type)

// Defines missing operations and a value mask for
// a bit-mask elements enum 'value_type'
#define BITMASK_DEFINE_VALUE_MASK(value_type, value_mask) \
    BITMASK_DETAIL_DEFINE_VALUE_MASK(value_type, value_mask) \
    BITMASK_DETAIL_DEFINE_OPS(value_type)

// Defines missing operations and a value mask based on max element for
// a bit-mask elements enum 'value_type'
#define BITMASK_DEFINE_MAX_ELEMENT(value_type, max_element) \
    BITMASK_DETAIL_DEFINE_MAX_ELEMENT(value_type, max_element) \
    BITMASK_DETAIL_DEFINE_OPS(value_type)
<commit_msg>Fix bitmask header<commit_after>#pragma once

/*
    Bitmask
    =======

    A generic implementation of the BitmaskType C++ concept
    http://en.cppreference.com/w/cpp/concept/BitmaskType

    Version: 1.1

    Latest version and documentation:
        https://github.com/oliora/bitmask

    Copyright (c) 2016-2017 Andrey Upadyshev (oliora@gmail.com)

    Distributed under the Boost Software License, Version 1.0.
    See http://www.boost.org/LICENSE_1_0.txt

    Changes history
    ---------------
    v1.1:
        - Change namespace from `boost` to `bitmask`
        - Add CMake package
          https://github.com/oliora/bitmask/issues/1
    v1.0:
        - Initial release
 */

#include <type_traits>
#include <functional>  // for std::hash
#include <limits>  // for std::numeric_limits
#include <cassert>

namespace bitmask_lib {

    namespace bitmask_detail {
        // Let's use std::void_t. It's introduced in C++17 but we can easily add it by ourself
        // See more at http://en.cppreference.com/w/cpp/types/void_t
        template<typename... Ts> struct make_void { typedef void type;};
        template<typename... Ts> using void_t = typename make_void<Ts...>::type;

        template<class T>
        struct underlying_type
        {
            static_assert(std::is_enum<T>::value, "T is not a enum type");

            using type = typename std::make_unsigned<typename std::underlying_type<T>::type>::type;
        };

        template<class T>
        using underlying_type_t = typename underlying_type<T>::type;

        template<class T, T MaxElement = T::_bitmask_max_element>
        struct mask_from_max_element
        {
            static constexpr underlying_type_t<T> max_element_value_ =
                static_cast<underlying_type_t<T>>(MaxElement);

            static_assert(max_element_value_ >= 0,
                          "Max element is negative");

            // If you really have to define a bitmask that uses the highest bit of signed type (i.e. the sign bit) then
            // define the value mask rather than the max element.
            static_assert(max_element_value_ <= (std::numeric_limits<typename std::underlying_type<T>::type>::max() >> 1) + 1,
                          "Max element is greater than the underlying type's highest bit");

            // `((value - 1) << 1) + 1` is used rather that simpler `(value << 1) - 1`
            // because latter overflows in case if `value` is the highest bit of the underlying type.
            static constexpr underlying_type_t<T> value =
                max_element_value_ ? ((max_element_value_ - 1) << 1) + 1 : 0;
        };

        template<class, class = void_t<>>
        struct has_max_element : std::false_type {};

        template<class T>
        struct has_max_element<T, void_t<decltype(T::_bitmask_max_element)>> : std::true_type {};

#if !defined _MSC_VER
        template<class, class = void_t<>>
        struct has_value_mask : std::false_type {};

        template<class T>
        struct has_value_mask<T, void_t<decltype(T::_bitmask_value_mask)>> : std::true_type {};
#else
        // MS Visual Studio 2015 (even Update 3) has weird support for expressions SFINAE
        // so I can't get a real check for `has_value_mask` to compile.
        template<class T>
        struct has_value_mask: std::integral_constant<bool, !has_max_element<T>::value> {};
#endif

        template<class T>
        struct is_valid_enum_definition : std::integral_constant<bool,
            !(has_value_mask<T>::value && has_max_element<T>::value)> {};

        template<class, class = void>
        struct enum_mask;

        template<class T>
        struct enum_mask<T, typename std::enable_if<has_max_element<T>::value>::type>
            : std::integral_constant<underlying_type_t<T>, mask_from_max_element<T>::value> {};

        template<class T>
        struct enum_mask<T, typename std::enable_if<has_value_mask<T>::value>::type>
            : std::integral_constant<underlying_type_t<T>, static_cast<underlying_type_t<T>>(T::_bitmask_value_mask)> {};

        template<class T>
        static constexpr underlying_type_t<T> disable_unused_function_warnings() noexcept
        {
            return (static_cast<T>(0) & static_cast<T>(0)).bits()
                & (static_cast<T>(0) | static_cast<T>(0)).bits()
                & (static_cast<T>(0) ^ static_cast<T>(0)).bits()
                & (~static_cast<T>(0)).bits()
                & bits(static_cast<T>(0));
        }

        template<class Assert>
        inline void constexpr_assert_failed(Assert&& a) noexcept { a(); }

        // When evaluated at compile time emits a compilation error if condition is not true.
        // Invokes the standard assert at run time.
        #define bitmask_constexpr_assert(cond) \
            ((void)((cond) ? 0 : (bitmask_lib::bitmask_detail::constexpr_assert_failed([](){ assert(!#cond);}), 0)))

        template<class T>
        inline constexpr T checked_value(T value, T mask)
        {
            return bitmask_constexpr_assert((value & ~mask) == 0), value;
        }
    }

    template<class T>
    inline constexpr bitmask_detail::underlying_type_t<T> get_enum_mask(const T&) noexcept
    {
        static_assert(bitmask_detail::is_valid_enum_definition<T>::value,
                      "Both of _bitmask_max_element and _bitmask_value_mask are specified");
        return bitmask_detail::enum_mask<T>::value;
    }

    template<class T>
    class bitmask
    {
    public:
        using value_type = T;
        using underlying_type = bitmask_detail::underlying_type_t<T>;

        static constexpr underlying_type mask_value = get_enum_mask(static_cast<value_type>(0));

        constexpr bitmask() noexcept = default;
        constexpr bitmask(std::nullptr_t) noexcept: m_bits{0} {}

        constexpr bitmask(value_type value) noexcept
        : m_bits{bitmask_detail::checked_value(static_cast<underlying_type>(value), mask_value)} {}

        constexpr underlying_type bits() const noexcept { return m_bits; }

        constexpr explicit operator bool() const noexcept { return bits() ? true : false; }

        constexpr bitmask operator ~ () const noexcept
        {
            return bitmask{std::true_type{}, ~m_bits & mask_value};
        }

        constexpr bitmask operator & (const bitmask& r) const noexcept
        {
            return bitmask{std::true_type{}, m_bits & r.m_bits};
        }

        constexpr bitmask operator | (const bitmask& r) const noexcept
        {
            return bitmask{std::true_type{}, m_bits | r.m_bits};
        }

        constexpr bitmask operator ^ (const bitmask& r) const noexcept
        {
            return bitmask{std::true_type{}, m_bits ^ r.m_bits};
        }

        bitmask& operator |= (const bitmask& r) noexcept
        {
            m_bits |= r.m_bits;
            return *this;
        }

        bitmask& operator &= (const bitmask& r) noexcept
        {
            m_bits &= r.m_bits;
            return *this;
        }

        bitmask& operator ^= (const bitmask& r) noexcept
        {
            m_bits ^= r.m_bits;
            return *this;
        }

    private:
        template<class U>
        constexpr bitmask(std::true_type, U bits) noexcept
        : m_bits(static_cast<underlying_type>(bits)) {}

        underlying_type m_bits = 0;
    };

    template<class T>
    inline constexpr bitmask<T>
    operator & (T l, const bitmask<T>& r) noexcept { return r & l; }

    template<class T>
    inline constexpr bitmask<T>
    operator | (T l, const bitmask<T>& r) noexcept { return r | l; }

    template<class T>
    inline constexpr bitmask<T>
    operator ^ (T l, const bitmask<T>& r) noexcept { return r ^ l; }

    template<class T>
    inline constexpr bool
    operator != (const bitmask<T>& l, const bitmask<T>& r) noexcept { return l.bits() != r.bits(); }

    template<class T>
    inline constexpr bool
    operator == (const bitmask<T>& l, const bitmask<T>& r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (T l, const bitmask<T>& r) noexcept { return static_cast<bitmask_detail::underlying_type_t<T>>(l) != r.bits(); }

    template<class T>
    inline constexpr bool
    operator == (T l, const bitmask<T>& r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (const bitmask<T>& l, T r) noexcept { return l.bits() != static_cast<bitmask_detail::underlying_type_t<T>>(r); }

    template<class T>
    inline constexpr bool operator == (const bitmask<T>& l, T r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (const bitmask_detail::underlying_type_t<T>& l, const bitmask<T>& r) noexcept { return l != r.bits(); }

    template<class T>
    inline constexpr bool
    operator == (const bitmask_detail::underlying_type_t<T>& l, const bitmask<T>& r) noexcept { return ! operator != (l, r); }

    template<class T>
    inline constexpr bool
    operator != (const bitmask<T>& l, const bitmask_detail::underlying_type_t<T>& r) noexcept { return l.bits() != r; }

    template<class T>
    inline constexpr bool
    operator == (const bitmask<T>& l, const bitmask_detail::underlying_type_t<T>& r) noexcept { return ! operator != (l, r); }

    // Allow `bitmask` to be be used as a map key
    template<class T>
    inline constexpr bool
    operator < (const bitmask<T>& l, const bitmask<T>& r) noexcept { return l.bits() < r.bits(); }

    template<class T>
    inline constexpr bitmask_detail::underlying_type_t<T>
    bits(const bitmask<T>& bm) noexcept { return bm.bits(); }

    // Implementation

    template<class T>
    constexpr typename bitmask<T>::underlying_type bitmask<T>::mask_value;
}

namespace std
{
    template<class T>
    struct hash<bitmask_lib::bitmask<T>>
    {
        constexpr std::size_t operator() (const bitmask_lib::bitmask<T>& op) const noexcept
        {
            using ut = typename bitmask_lib::bitmask<T>::underlying_type;
            return std::hash<ut>{}(op.bits());
        }
    };
}

// Implementation detail macros

#define BITMASK_DETAIL_DEFINE_OPS(value_type) \
    inline constexpr bitmask_lib::bitmask<value_type> operator & (value_type l, value_type r) noexcept { return bitmask_lib::bitmask<value_type>{l} & r; } \
    inline constexpr bitmask_lib::bitmask<value_type> operator | (value_type l, value_type r) noexcept { return bitmask_lib::bitmask<value_type>{l} | r; } \
    inline constexpr bitmask_lib::bitmask<value_type> operator ^ (value_type l, value_type r) noexcept { return bitmask_lib::bitmask<value_type>{l} ^ r; } \
    inline constexpr bitmask_lib::bitmask<value_type> operator ~ (value_type op) noexcept { return ~bitmask_lib::bitmask<value_type>{op}; }                \
    inline constexpr bitmask_lib::bitmask<value_type>::underlying_type bits(value_type op) noexcept { return bitmask_lib::bitmask<value_type>{op}.bits(); }\
    using unused_bitmask_ ## value_type ## _t_ = decltype(bitmask_lib::bitmask_detail::disable_unused_function_warnings<value_type>());

#define BITMASK_DETAIL_DEFINE_VALUE_MASK(value_type, value_mask) \
    inline constexpr bitmask_lib::bitmask_detail::underlying_type_t<value_type> get_enum_mask(value_type) noexcept { return value_mask; }

#define BITMASK_DETAIL_DEFINE_MAX_ELEMENT(value_type, max_element) \
    inline constexpr bitmask_lib::bitmask_detail::underlying_type_t<value_type> get_enum_mask(value_type) noexcept { \
        return bitmask_lib::bitmask_detail::mask_from_max_element<value_type, value_type::max_element>::value;       \
    }

// Public macros

// Defines missing operations for a bit-mask elements enum 'value_type'
// Value mask is taken from 'value_type' definition. One should has either
// '_bitmask_value_mask' or '_bitmask_max_element' element defined.
#define BITMASK_DEFINE(value_type) \
    BITMASK_DETAIL_DEFINE_OPS(value_type)

// Defines missing operations and a value mask for
// a bit-mask elements enum 'value_type'
#define BITMASK_DEFINE_VALUE_MASK(value_type, value_mask) \
    BITMASK_DETAIL_DEFINE_VALUE_MASK(value_type, value_mask) \
    BITMASK_DETAIL_DEFINE_OPS(value_type)

// Defines missing operations and a value mask based on max element for
// a bit-mask elements enum 'value_type'
#define BITMASK_DEFINE_MAX_ELEMENT(value_type, max_element) \
    BITMASK_DETAIL_DEFINE_MAX_ELEMENT(value_type, max_element) \
    BITMASK_DETAIL_DEFINE_OPS(value_type)
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_TEMPORARY_HPP
#define ETL_TEMPORARY_HPP

#include "config.hpp"       //configuration of ETL
#include "traits_lite.hpp"  //type traits
#include "stop.hpp"

namespace etl {

template<typename E, cpp_enable_if(has_direct_access<E>::value || !create_temporary::value)>
decltype(auto) make_temporary(E&& expr){
    return std::forward<E>(expr);
}

template<typename E, cpp_enable_if(!has_direct_access<E>::value && create_temporary::value && !decay_traits<E>::is_fast)>
decltype(auto) make_temporary(E&& expr){
    //Sizes will be directly propagated
    return dyn_matrix<value_t<E>, decay_traits<E>::dimensions()>{std::forward<E>(expr)};
}

template<typename E, typename Sequence>
struct build_fast_dyn_matrix_type;

template<typename E, std::size_t... I>
struct build_fast_dyn_matrix_type<E, std::index_sequence<I...>> {
    using type = fast_dyn_matrix<value_t<E>, decay_traits<E>::template dim<I>()...>;
};

template<typename E, cpp_enable_if(!has_direct_access<E>::value && create_temporary::value && decay_traits<E>::is_fast)>
decltype(auto) make_temporary(E&& expr){
    return typename build_fast_dyn_matrix_type<E, std::make_index_sequence<decay_traits<E>::dimensions()>>::type{std::forward<E>(expr)};
}

} //end of namespace etl

#endif
<commit_msg>More temporary utilities<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_TEMPORARY_HPP
#define ETL_TEMPORARY_HPP

#include "config.hpp"       //configuration of ETL
#include "traits_lite.hpp"  //type traits
#include "stop.hpp"

namespace etl {

template<typename E, typename Sequence>
struct build_fast_dyn_matrix_type;

template<typename E, std::size_t... I>
struct build_fast_dyn_matrix_type<E, std::index_sequence<I...>> {
    using type = fast_dyn_matrix<value_t<E>, decay_traits<E>::template dim<I>()...>;
};

template<typename E, cpp_enable_if(decay_traits<E>::is_fast)>
decltype(auto) force_temporary(E&& expr){
    return typename build_fast_dyn_matrix_type<E, std::make_index_sequence<decay_traits<E>::dimensions()>>::type{std::forward<E>(expr)};
}

template<typename E, cpp_disable_if(decay_traits<E>::is_fast)>
decltype(auto) force_temporary(E&& expr){
    //Sizes will be directly propagated
    return dyn_matrix<value_t<E>, decay_traits<E>::dimensions()>{std::forward<E>(expr)};
}

template<typename E, cpp_enable_if(has_direct_access<E>::value || !create_temporary::value)>
decltype(auto) make_temporary(E&& expr){
    return std::forward<E>(expr);
}

template<typename E, cpp_disable_if(has_direct_access<E>::value || !create_temporary::value)>
decltype(auto) make_temporary(E&& expr){
    return force_temporary(std::forward<E>(expr));
}

} //end of namespace etl

#endif
<|endoftext|>


<commit_before>/*!
 * \file TermPartOrdGraph_test.cc
 *
 * \brief Test for the TermPartOrdGraph class.
 *
 * \date Started: 11/20/15
 *
 * \authors Michelle Strout
 *
 * Copyright (c) 2015, University of Arizona

 * All rights reserved.

 * See ../../COPYING for details.

 */

#include "expression.h"
#include "TermPartOrdGraph.h"

#include <gtest/gtest.h>
#include <utility>
#include <iostream>
#include <fstream>

using iegenlib::TermPartOrdGraph;
using iegenlib::TupleVarTerm;
using iegenlib::Term;
using iegenlib::VarTerm;
using iegenlib::UFCallTerm;
using iegenlib::TupleExpTerm;
using iegenlib::Exp;

/*      TermPartOrdGraph g;
 *      UFCallTerm uf = new UFCallTerm( ... );
 *      TupleVarTerm tv = new TupleVarTerm( ... );
 *      g.insertTerm( uf );
 *      g.insertTerm( tv );
 *      g.insertTerm( uf );     // Will do object comparison and only keep one.
 *
 *      g.doneInsertingTerms();
 *
 *      // Insertions of orderings can only come after doneInsertingTerms.
 *      g.insertLTE( uf, tv);   // (*uf) <= (*tv)
 *      g.insertLT( uf, tv);    // (*uf) < (*tv)
 *      g.insertEqual( uf,tv ); // Will cause an error in this case.
 *
 *      // Indicating a term is non-negative can happen at anytime
 *      // after the term has been inserted.
 *      g.termNonNegative( tv );
 *
 *      //====== Queries ======
 *
 *      if (g.isNonNegative(uf)) { ... }
 *
 *      std::set<UFCallTerm*> ufTerms = g.getUniqueUFCallTerms();
 *      for (std::set<Term*>::const_iterator iter1 = ufTerms.begin();
 *              iter1!=ufTerms.end(); iter1++) {
 *          for (std::set<Term*>::const_iterator iter2 = ufTerms.begin();
 *                  iter2!=ufTerms.end(); iter2++) {
 *              if (g.isLT(*iter1, *iter2)) {
 *                  ...
 *              }
 *          }
 *      }
 */

#pragma mark TermPartOrdGraphToString
// Test the toString method.
TEST(TermPartOrdGraphTest, TermPartOrdGraphToString) {

    TermPartOrdGraph g;
    VarTerm * v = new VarTerm( "N" );
    g.insertTerm( v );

    EXPECT_EQ("TermPartOrdGraph:\n\tmDoneInsertingTerms = 0\n"
              "\tmNumTerms = 1\n\tmNonNegativeTerms = \n",
              g.toString());
    //std::cout << g.toString();

    delete v;
}

#pragma mark TermPartOrdGraphIsNonNegative
// Test the toString method.
TEST(TermPartOrdGraphTest, TermPartOrdGraphIsNonNegative) {

    TermPartOrdGraph g;
    VarTerm * v = new VarTerm( "N" );
    g.insertTerm( v );
    g.termNonNegative( v );

    UFCallTerm* uf_call = new UFCallTerm("tau", 2); // tau(i,j)
    Exp *tau_arg_1 = new Exp();
    tau_arg_1->addTerm(new VarTerm("i"));
    uf_call->setParamExp(0,tau_arg_1);
    Exp *tau_arg_2 = new Exp();
    tau_arg_2->addTerm(new VarTerm("j"));
    uf_call->setParamExp(1,tau_arg_2);

    g.insertTerm( uf_call );

    std::cout << g.toString();

    EXPECT_EQ(true, g.isNonNegative( v ));
    EXPECT_EQ(false, g.isNonNegative( uf_call ));

    delete v;
    delete uf_call;
}

<commit_msg>Testing unique term set creation in TermPartOrdGraph_test.cc.<commit_after>/*!
 * \file TermPartOrdGraph_test.cc
 *
 * \brief Test for the TermPartOrdGraph class.
 *
 * \date Started: 11/20/15
 *
 * \authors Michelle Strout
 *
 * Copyright (c) 2015, University of Arizona

 * All rights reserved.

 * See ../../COPYING for details.

 */

#include "expression.h"
#include "TermPartOrdGraph.h"

#include <gtest/gtest.h>
#include <utility>
#include <iostream>
#include <fstream>

using iegenlib::TermPartOrdGraph;
using iegenlib::TupleVarTerm;
using iegenlib::Term;
using iegenlib::VarTerm;
using iegenlib::UFCallTerm;
using iegenlib::TupleExpTerm;
using iegenlib::Exp;

/*      TermPartOrdGraph g;
 *      UFCallTerm uf = new UFCallTerm( ... );
 *      TupleVarTerm tv = new TupleVarTerm( ... );
 *      g.insertTerm( uf );
 *      g.insertTerm( tv );
 *      g.insertTerm( uf );     // Will do object comparison and only keep one.
 *
 *      g.doneInsertingTerms();
 *
 *      // Insertions of orderings can only come after doneInsertingTerms.
 *      g.insertLTE( uf, tv);   // (*uf) <= (*tv)
 *      g.insertLT( uf, tv);    // (*uf) < (*tv)
 *      g.insertEqual( uf,tv ); // Will cause an error in this case.
 *
 *      // Indicating a term is non-negative can happen at anytime
 *      // after the term has been inserted.
 *      g.termNonNegative( tv );
 *
 *      //====== Queries ======
 *
 *      if (g.isNonNegative(uf)) { ... }
 *
 *      std::set<UFCallTerm*> ufTerms = g.getUniqueUFCallTerms();
 *      for (std::set<Term*>::const_iterator iter1 = ufTerms.begin();
 *              iter1!=ufTerms.end(); iter1++) {
 *          for (std::set<Term*>::const_iterator iter2 = ufTerms.begin();
 *                  iter2!=ufTerms.end(); iter2++) {
 *              if (g.isLT(*iter1, *iter2)) {
 *                  ...
 *              }
 *          }
 *      }
 */

#pragma mark TermPartOrdGraphToString
// Test the toString method.
TEST(TermPartOrdGraphTest, TermPartOrdGraphToString) {

    TermPartOrdGraph g;
    VarTerm * v = new VarTerm( "N" );
    g.insertTerm( v );

    EXPECT_EQ("TermPartOrdGraph:\n\tmDoneInsertingTerms = 0\n"
              "\tmNumTerms = 1\n\tmNonNegativeTerms = \n"
              "\tmUFCallTerm2IntMap = \n\tmTupleVarTerm2IntMap ="
              " \n\tmVarTerm2IntMap = \n\t\tterm = N, id = 0\n",
              g.toString());
    //std::cout << g.toString();

    delete v;
}

#pragma mark TermPartOrdGraphIsNonNegative
// Test the toString method.
TEST(TermPartOrdGraphTest, TermPartOrdGraphIsNonNegative) {

    TermPartOrdGraph g;
    VarTerm * v = new VarTerm( "N" );
    g.insertTerm( v );
    g.termNonNegative( v );

    UFCallTerm* uf_call = new UFCallTerm("tau", 2); // tau(i,j)
    Exp *tau_arg_1 = new Exp();
    tau_arg_1->addTerm(new VarTerm("i"));
    uf_call->setParamExp(0,tau_arg_1);
    Exp *tau_arg_2 = new Exp();
    tau_arg_2->addTerm(new VarTerm("j"));
    uf_call->setParamExp(1,tau_arg_2);

    g.insertTerm( uf_call );

    //std::cout << g.toString();

    EXPECT_EQ(true, g.isNonNegative( v ));
    EXPECT_EQ(false, g.isNonNegative( uf_call ));

    delete v;
    delete uf_call;
}

#pragma mark TermPartOrdGraphUniqueTerms
// Test the toString method.
TEST(TermPartOrdGraphTest, TermPartOrdGraphUniqueTerms) {

    TermPartOrdGraph g;

    // term = N
    VarTerm * v = new VarTerm( 3, "N" );
    g.insertTerm( v );
    delete v;
    g.termNonNegative( v );
    VarTerm * v2 = new VarTerm( -1, "N" );
    g.insertTerm( v2 );
    delete v2;

    // Check that non-negative stayed the same.
    EXPECT_EQ(true, g.isNonNegative( v ));

    {
    // Check the size of the unique sets.
    std::set<UFCallTerm*> ufCallTermSet = g.getUniqueUFCallTerms();
    EXPECT_EQ(0,ufCallTermSet.size());
    std::set<Term*> termSet = g.getAllUniqueTerms();
    EXPECT_EQ(1,termSet.size());
    }

    {
    // term = tau(i,j)
    UFCallTerm* uf_call = new UFCallTerm("tau", 2);
    Exp *tau_arg_1 = new Exp();
    tau_arg_1->addTerm(new VarTerm("i"));
    uf_call->setParamExp(0,tau_arg_1);
    Exp *tau_arg_2 = new Exp();
    tau_arg_2->addTerm(new VarTerm("j"));
    uf_call->setParamExp(1,tau_arg_2);

    g.insertTerm( uf_call );
    delete uf_call;
    }

    {
    // Check the size of the unique sets.
    std::set<UFCallTerm*> ufCallTermSet = g.getUniqueUFCallTerms();
    EXPECT_EQ(1,ufCallTermSet.size());
    std::set<Term*> termSet = g.getAllUniqueTerms();
    EXPECT_EQ(2,termSet.size());
    }

    { // Inserting same thing twice on purpose.
    // term = tau(i,j)
    UFCallTerm* uf_call = new UFCallTerm("tau", 2);
    Exp *tau_arg_1 = new Exp();
    tau_arg_1->addTerm(new VarTerm("i"));
    uf_call->setParamExp(0,tau_arg_1);
    Exp *tau_arg_2 = new Exp();
    tau_arg_2->addTerm(new VarTerm("j"));
    uf_call->setParamExp(1,tau_arg_2);

    g.insertTerm( uf_call );
    delete uf_call;
    }

    {
    // Check the size of the unique sets.
    std::set<UFCallTerm*> ufCallTermSet = g.getUniqueUFCallTerms();
    EXPECT_EQ(1,ufCallTermSet.size());
    std::set<Term*> termSet = g.getAllUniqueTerms();
    EXPECT_EQ(2,termSet.size());
    }

    {
    // term = g(3 __tv3)
    UFCallTerm* uf_call = new UFCallTerm("g", 1);
    Exp *g0 = new Exp();
    g0->addTerm(new TupleVarTerm(3, 3));
    uf_call->setParamExp(0,g0);

    g.insertTerm( uf_call );
    delete uf_call;
    }

    {
    // Check the size of the unique sets.
    std::set<UFCallTerm*> ufCallTermSet = g.getUniqueUFCallTerms();
    EXPECT_EQ(2,ufCallTermSet.size());
    std::set<Term*> termSet = g.getAllUniqueTerms();
    EXPECT_EQ(3,termSet.size());
    }

    {
    // term = g(2 __tv3)
    UFCallTerm* uf_call = new UFCallTerm("g", 1);
    Exp *g0 = new Exp();
    g0->addTerm(new TupleVarTerm(2, 3));
    uf_call->setParamExp(0,g0);

    g.insertTerm( uf_call );
    delete uf_call;
    }

    {
    // Check the size of the unique sets.
    std::set<UFCallTerm*> ufCallTermSet = g.getUniqueUFCallTerms();
    EXPECT_EQ(3,ufCallTermSet.size());
    std::set<Term*> termSet = g.getAllUniqueTerms();
    EXPECT_EQ(4,termSet.size());
    }

    std::cout << g.toString();

}
<|endoftext|>


<commit_before>/* Copyright(C)
* For free
* All right reserved
*
*/
/**
* @file LogMessage.cpp
* @brief 日志消息类
* @author highway-9, 787280310@qq.com
* @version 1.1.0
* @date 2016-01-23
*/

#include "LogMessage.h"
#include "LogImpl.h"
#include "Utils.h"
#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include <string>

LogMessage::LogMessage(const char* filePath,
                       const char* function,
                       unsigned long line,
                       unsigned int priorityLevel)
    : m_filePath(filePath),
    m_function(function),
    m_line(line),
    m_priorityLevel(priorityLevel)
{
    // Do nothing
}

void LogMessage::log(const char* msg, ...)
{
    char buf[4096] = {'\0'};
    va_list args;
    va_start(args, msg);
    vsprintf(buf, msg, args);
    va_end(args);

    logPrintImpl(m_filePath, m_function, m_line, m_priorityLevel, std::string(buf));
}

LogStream LogMessage::log() const
{
    return LogStream(m_filePath, m_function, m_line, m_priorityLevel);
}

void LogMessage::logPrintImpl(const std::string& filePath,
                              const std::string& function,
                              unsigned long line,
                              unsigned int priorityLevel,
                              const std::string& content)
{
    std::string logContent = createLogContent(filePath, function, line, content);
    bool ok = LogImpl::getInstance()->logPrint(priorityLevel, logContent);
    if (!ok)
    {
        std::cout << "Print log failed, log content: " << logContent << std::endl;
    }
}

std::string LogMessage::createLogContent(const std::string& filePath,
                                         const std::string& function,
                                         unsigned long line,
                                         const std::string& content)
{
    std::string strLine = utils::String::uint64ToString(line);
    std::string strFilePath = filePath;
    int pos = strFilePath.find_last_of("/");
    std::string logContent = strFilePath.substr(pos + 1) + " " + function + "(" + strLine + ") " + content;

    return logContent;
}
<commit_msg>Update clog<commit_after>/* Copyright(C)
* For free
* All right reserved
*
*/
/**
* @file LogMessage.cpp
* @brief 日志消息类
* @author highway-9, 787280310@qq.com
* @version 1.1.0
* @date 2016-01-23
*/

#include "LogMessage.h"
#include "LogImpl.h"
#include "Utils.h"
#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include <string>

LogMessage::LogMessage(const char* filePath,
                       const char* function,
                       unsigned long line,
                       unsigned int priorityLevel)
    : m_filePath(filePath),
    m_function(function),
    m_line(line),
    m_priorityLevel(priorityLevel)
{
    // Do nothing
}

void LogMessage::log(const char* msg, ...)
{
    char buf[4096] = {'\0'};
    va_list args;
    va_start(args, msg);
    vsprintf(buf, msg, args);
    va_end(args);

    logPrintImpl(m_filePath, m_function, m_line, m_priorityLevel, buf);
}

LogStream LogMessage::log() const
{
    return LogStream(m_filePath, m_function, m_line, m_priorityLevel);
}

void LogMessage::logPrintImpl(const std::string& filePath,
                              const std::string& function,
                              unsigned long line,
                              unsigned int priorityLevel,
                              const std::string& content)
{
    std::string logContent = createLogContent(filePath, function, line, content);
    bool ok = LogImpl::getInstance()->logPrint(priorityLevel, logContent);
    if (!ok)
    {
        std::cout << "Print log failed, log content: " << logContent << std::endl;
    }
}

std::string LogMessage::createLogContent(const std::string& filePath,
                                         const std::string& function,
                                         unsigned long line,
                                         const std::string& content)
{
    std::string strLine = utils::String::uint64ToString(line);
    std::string strFilePath = filePath;
    int pos = strFilePath.find_last_of("/");
    std::string logContent = strFilePath.substr(pos + 1) + " " + function + "(" + strLine + ") " + content;

    return logContent;
}
<|endoftext|>


<commit_before>//===- SyntaxColoring.cpp - Routines for syntax coloring ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/IDE/SyntaxColoring.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/Token.h"
#include "swift/Subsystems.h"
#include "llvm/Support/MemoryBuffer.h"
#include <vector>

using namespace swift;
using namespace ide;

void SyntaxColorWalker::anchor() {}

struct SyntaxColoringContext::Implementation {
  std::vector<SyntaxNode> TokenNodes;
};

SyntaxColoringContext::SyntaxColoringContext(SourceManager &SM,
                                             unsigned BufferID,
                                             TranslationUnit &TU)
  : Impl(*new Implementation()),
    TU(TU) {
  std::vector<Token> Tokens = swift::tokenize(SM, BufferID, /*Offset=*/0,
                                              /*EndOffset=*/0,
                                              /*KeepComments=*/true,
                                           /*TokenizeInterpolatedString=*/true);
  std::vector<SyntaxNode> Nodes;
  for (auto &Tok : Tokens) {
    SyntaxNodeKind Kind;
    switch(Tok.getKind()) {
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
#include "swift/Parse/Tokens.def"
#undef KEYWORD

    case tok::identifier: Kind = SyntaxNodeKind::Identifier; break;
    case tok::dollarident: Kind = SyntaxNodeKind::DollarIdent; break;
    case tok::integer_literal: Kind = SyntaxNodeKind::Integer; break;
    case tok::floating_literal: Kind = SyntaxNodeKind::Floating; break;
    case tok::string_literal: Kind = SyntaxNodeKind::String; break;
    case tok::character_literal: Kind = SyntaxNodeKind::Character; break;
    case tok::comment:
      if (Tok.getText().startswith("//"))
        Kind = SyntaxNodeKind::CommentLine;
      else
        Kind = SyntaxNodeKind::CommentBlock;
      break;

    default:
      continue;
    }

    assert(Tok.getLoc().isValid());
    assert(Nodes.empty() || SM.isBeforeInBuffer(Nodes.back().Range.getStart(),
                                                Tok.getLoc()));
    Nodes.emplace_back(Kind, CharSourceRange(Tok.getLoc(), Tok.getLength()));
  }

  Impl.TokenNodes = std::move(Nodes);
}

SyntaxColoringContext::~SyntaxColoringContext() {
  delete &Impl;
}

namespace {

class ColorASTWalker : public ASTWalker {
  const SourceManager &SM;

public:
  SyntaxColorWalker &SCWalker;
  ArrayRef<SyntaxNode> TokenNodes;

  ColorASTWalker(const SourceManager &SM, SyntaxColorWalker &SCWalker)
      : SM(SM), SCWalker(SCWalker) { }

  void visitTranslationUnit(TranslationUnit &TU, ArrayRef<SyntaxNode> Tokens);

  virtual bool walkToTypeReprPre(TypeRepr *T);

private:
  enum PassNodesBehavior {
    //Pass all nodes up to but not including the location
    ExcludeNodeAtLocation,
    //Pass all nodes up to and including the location
    IncludeNodeAtLocation,
    //Like ExcludeNodeAtLocation, and skip past any node at the location
    DisplaceNodeAtLocation
  };
  bool passTokenNodesUntil(SourceLoc Loc, PassNodesBehavior Behavior);
  bool passNonTokenNode(const SyntaxNode &Node);
  bool passNode(const SyntaxNode &Node);
};

} // anonymous namespace

bool SyntaxColoringContext::walk(SyntaxColorWalker &Walker) {
  ColorASTWalker ASTWalk(TU.Ctx.SourceMgr, Walker);
  ASTWalk.visitTranslationUnit(TU, Impl.TokenNodes);
  return true;
}

void ColorASTWalker::visitTranslationUnit(TranslationUnit &TU,
                                          ArrayRef<SyntaxNode> Tokens) {
  TokenNodes = Tokens;
  for (Decl *D : TU.Decls)
    D->walk(*this);

  // Pass the rest of the token nodes.
  for (auto &TokNode : TokenNodes)
    passNode(TokNode);
}

bool ColorASTWalker::walkToTypeReprPre(TypeRepr *T) {
  if (IdentTypeRepr *IdT = dyn_cast<IdentTypeRepr>(T)) {
    for (auto &comp : IdT->Components) {
      if (!passNonTokenNode({ SyntaxNodeKind::TypeId,
                              CharSourceRange(comp.getIdLoc(),
                                              comp.getIdentifier().getLength())
                            }))
        return false;
    }
  }
  return true;
}

bool ColorASTWalker::passTokenNodesUntil(SourceLoc Loc,
                                         PassNodesBehavior Behavior) {
  assert(Loc.isValid());
  unsigned I = 0;
  for (unsigned E = TokenNodes.size(); I != E; ++I) {
    SourceLoc TokLoc = TokenNodes[I].Range.getStart();
    if (SM.isBeforeInBuffer(Loc, TokLoc)) {
      break;
    }
    if (TokLoc == Loc && Behavior != IncludeNodeAtLocation) {
      if (Behavior == DisplaceNodeAtLocation) {
        //Skip past the node directly at the specified location, allowing the
        //caller to effectively replace it.
        ++I;
      }
      break;
    }
    if (!passNode(TokenNodes[I]))
      return false;
  }

  TokenNodes = TokenNodes.slice(I);
  return true;
}

bool ColorASTWalker::passNonTokenNode(const SyntaxNode &Node) {
  if (!passTokenNodesUntil(Node.Range.getStart(), DisplaceNodeAtLocation))
    return false;
  if (!passNode(Node))
    return false;
  return true;
}

bool ColorASTWalker::passNode(const SyntaxNode &Node) {
  SCWalker.walkToNodePre(Node);
  if (!SCWalker.walkToNodePost(Node))
    return false;
  return true;
}
<commit_msg>Some code formatting fixes.<commit_after>//===- SyntaxColoring.cpp - Routines for syntax coloring ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/IDE/SyntaxColoring.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Module.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/Token.h"
#include "swift/Subsystems.h"
#include "llvm/Support/MemoryBuffer.h"
#include <vector>

using namespace swift;
using namespace ide;

void SyntaxColorWalker::anchor() {}

struct SyntaxColoringContext::Implementation {
  std::vector<SyntaxNode> TokenNodes;
};

SyntaxColoringContext::SyntaxColoringContext(SourceManager &SM,
                                             unsigned BufferID,
                                             TranslationUnit &TU)
  : Impl(*new Implementation()),
    TU(TU) {
  std::vector<Token> Tokens = swift::tokenize(SM, BufferID, /*Offset=*/0,
                                              /*EndOffset=*/0,
                                              /*KeepComments=*/true,
                                           /*TokenizeInterpolatedString=*/true);
  std::vector<SyntaxNode> Nodes;
  for (auto &Tok : Tokens) {
    SyntaxNodeKind Kind;
    switch(Tok.getKind()) {
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
#include "swift/Parse/Tokens.def"
#undef KEYWORD

    case tok::identifier: Kind = SyntaxNodeKind::Identifier; break;
    case tok::dollarident: Kind = SyntaxNodeKind::DollarIdent; break;
    case tok::integer_literal: Kind = SyntaxNodeKind::Integer; break;
    case tok::floating_literal: Kind = SyntaxNodeKind::Floating; break;
    case tok::string_literal: Kind = SyntaxNodeKind::String; break;
    case tok::character_literal: Kind = SyntaxNodeKind::Character; break;
    case tok::comment:
      if (Tok.getText().startswith("//"))
        Kind = SyntaxNodeKind::CommentLine;
      else
        Kind = SyntaxNodeKind::CommentBlock;
      break;

    default:
      continue;
    }

    assert(Tok.getLoc().isValid());
    assert(Nodes.empty() || SM.isBeforeInBuffer(Nodes.back().Range.getStart(),
                                                Tok.getLoc()));
    Nodes.emplace_back(Kind, CharSourceRange(Tok.getLoc(), Tok.getLength()));
  }

  Impl.TokenNodes = std::move(Nodes);
}

SyntaxColoringContext::~SyntaxColoringContext() {
  delete &Impl;
}

namespace {

class ColorASTWalker : public ASTWalker {
  const SourceManager &SM;

public:
  SyntaxColorWalker &SCWalker;
  ArrayRef<SyntaxNode> TokenNodes;

  ColorASTWalker(const SourceManager &SM, SyntaxColorWalker &SCWalker)
      : SM(SM), SCWalker(SCWalker) { }

  void visitTranslationUnit(TranslationUnit &TU, ArrayRef<SyntaxNode> Tokens);

  virtual bool walkToTypeReprPre(TypeRepr *T);

private:
  enum PassNodesBehavior {
    /// Pass all nodes up to but not including the location.
    ExcludeNodeAtLocation,
    /// Pass all nodes up to and including the location.
    IncludeNodeAtLocation,
    /// Like ExcludeNodeAtLocation, and skip past any node at the location.
    DisplaceNodeAtLocation
  };
  bool passTokenNodesUntil(SourceLoc Loc, PassNodesBehavior Behavior);
  bool passNonTokenNode(const SyntaxNode &Node);
  bool passNode(const SyntaxNode &Node);
};

} // anonymous namespace

bool SyntaxColoringContext::walk(SyntaxColorWalker &Walker) {
  ColorASTWalker ASTWalk(TU.Ctx.SourceMgr, Walker);
  ASTWalk.visitTranslationUnit(TU, Impl.TokenNodes);
  return true;
}

void ColorASTWalker::visitTranslationUnit(TranslationUnit &TU,
                                          ArrayRef<SyntaxNode> Tokens) {
  TokenNodes = Tokens;
  for (Decl *D : TU.Decls)
    D->walk(*this);

  // Pass the rest of the token nodes.
  for (auto &TokNode : TokenNodes)
    passNode(TokNode);
}

bool ColorASTWalker::walkToTypeReprPre(TypeRepr *T) {
  if (IdentTypeRepr *IdT = dyn_cast<IdentTypeRepr>(T)) {
    for (auto &comp : IdT->Components) {
      if (!passNonTokenNode({ SyntaxNodeKind::TypeId,
                              CharSourceRange(comp.getIdLoc(),
                                              comp.getIdentifier().getLength())
                            }))
        return false;
    }
  }
  return true;
}

bool ColorASTWalker::passTokenNodesUntil(SourceLoc Loc,
                                         PassNodesBehavior Behavior) {
  assert(Loc.isValid());
  unsigned I = 0;
  for (unsigned E = TokenNodes.size(); I != E; ++I) {
    SourceLoc TokLoc = TokenNodes[I].Range.getStart();
    if (SM.isBeforeInBuffer(Loc, TokLoc)) {
      break;
    }
    if (TokLoc == Loc && Behavior != IncludeNodeAtLocation) {
      if (Behavior == DisplaceNodeAtLocation) {
        // Skip past the node directly at the specified location, allowing the
        // caller to effectively replace it.
        ++I;
      }
      break;
    }
    if (!passNode(TokenNodes[I]))
      return false;
  }

  TokenNodes = TokenNodes.slice(I);
  return true;
}

bool ColorASTWalker::passNonTokenNode(const SyntaxNode &Node) {
  if (!passTokenNodesUntil(Node.Range.getStart(), DisplaceNodeAtLocation))
    return false;
  if (!passNode(Node))
    return false;
  return true;
}

bool ColorASTWalker::passNode(const SyntaxNode &Node) {
  SCWalker.walkToNodePre(Node);
  if (!SCWalker.walkToNodePost(Node))
    return false;
  return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpaceXformer.h"
#include "SkSweepGradient.h"

#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"

SkSweepGradient::SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1,
                                 const Descriptor& desc)
    : SkGradientShaderBase(desc, SkMatrix::MakeTrans(-center.x(), -center.y()))
    , fCenter(center)
    , fTBias(-t0)
    , fTScale(1 / (t1 - t0))
{
    SkASSERT(t0 < t1);
}

SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
    if (info) {
        commonAsAGradient(info);
        info->fPoint[0] = fCenter;
    }
    return kSweep_GradientType;
}

sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
    DescriptorScope desc;
    if (!desc.unflatten(buffer)) {
        return nullptr;
    }
    const SkPoint center = buffer.readPoint();

    SkScalar startAngle = 0,
               endAngle = 360;
    if (!buffer.isVersionLT(SkReadBuffer::kTileInfoInSweepGradient_Version)) {
        const auto tBias  = buffer.readScalar(),
                   tScale = buffer.readScalar();
        startAngle = -tBias * 360;
          endAngle = (1 / tScale - tBias) * 360;
    }

    return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
                                       std::move(desc.fColorSpace), desc.fPos, desc.fCount,
                                       desc.fTileMode, startAngle, endAngle,
                                       desc.fGradFlags, desc.fLocalMatrix);
}

void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writePoint(fCenter);
    buffer.writeScalar(fTBias);
    buffer.writeScalar(fTScale);
}

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

#if SK_SUPPORT_GPU

#include "SkGr.h"
#include "GrShaderCaps.h"
#include "gl/GrGLContext.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"

class GrSweepGradient : public GrGradientEffect {
public:
    class GLSLSweepProcessor;

    static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar tBias,
                                           SkScalar tScale) {
        auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args, tBias, tScale));
        return processor->isValid() ? std::move(processor) : nullptr;
    }

    const char* name() const override { return "Sweep Gradient"; }

    sk_sp<GrFragmentProcessor> clone() const override {
        return sk_sp<GrFragmentProcessor>(new GrSweepGradient(*this));
    }

private:
    explicit GrSweepGradient(const CreateArgs& args, SkScalar tBias, SkScalar tScale)
            : INHERITED(args, args.fShader->colorsAreOpaque())
            , fTBias(tBias)
            , fTScale(tScale){
        this->initClassID<GrSweepGradient>();
    }

    explicit GrSweepGradient(const GrSweepGradient& that)
            : INHERITED(that)
            , fTBias(that.fTBias)
            , fTScale(that.fTScale) {
        this->initClassID<GrSweepGradient>();
    }

    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;

    virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                       GrProcessorKeyBuilder* b) const override;

     bool onIsEqual(const GrFragmentProcessor& base) const override {
         const GrSweepGradient& fp = base.cast<GrSweepGradient>();
         return INHERITED::onIsEqual(base)
             && fTBias == fp.fTBias
             && fTScale == fp.fTScale;
     }

    GR_DECLARE_FRAGMENT_PROCESSOR_TEST

    SkScalar fTBias;
    SkScalar fTScale;

    typedef GrGradientEffect INHERITED;
};

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

class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor {
public:
    GLSLSweepProcessor(const GrProcessor&)
        : fCachedTBias(SK_FloatNaN)
        , fCachedTScale(SK_FloatNaN) {}

    void emitCode(EmitArgs&) override;

    static void GenKey(const GrProcessor& processor, const GrShaderCaps&,
                       GrProcessorKeyBuilder* b) {
        b->add32(GenBaseGradientKey(processor));
    }

protected:
    void onSetData(const GrGLSLProgramDataManager& pdman,
                   const GrFragmentProcessor& processor) override {
        INHERITED::onSetData(pdman, processor);
        const GrSweepGradient& data = processor.cast<GrSweepGradient>();

        if (fCachedTBias != data.fTBias || fCachedTScale != data.fTScale) {
            fCachedTBias  = data.fTBias;
            fCachedTScale = data.fTScale;
            pdman.set2f(fTBiasScaleUni, fCachedTBias, fCachedTScale);
        }
    }

private:
    UniformHandle fTBiasScaleUni;

    // Uploaded uniform values.
    float fCachedTBias,
          fCachedTScale;

    typedef GrGradientEffect::GLSLProcessor INHERITED;
};

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

GrGLSLFragmentProcessor* GrSweepGradient::onCreateGLSLInstance() const {
    return new GrSweepGradient::GLSLSweepProcessor(*this);
}

void GrSweepGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                            GrProcessorKeyBuilder* b) const {
    GrSweepGradient::GLSLSweepProcessor::GenKey(*this, caps, b);
}

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

GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient);

#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrSweepGradient::TestCreate(GrProcessorTestData* d) {
    SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};

    RandomGradientParams params(d->fRandom);
    auto shader = params.fUseColors4f ?
        SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors4f, params.fColorSpace,
                                    params.fStops, params.fColorCount) :
        SkGradientShader::MakeSweep(center.fX, center.fY,  params.fColors,
                                    params.fStops, params.fColorCount);
    GrTest::TestAsFPArgs asFPArgs(d);
    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
    GrAlwaysAssert(fp);
    return fp;
}
#endif

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

void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) {
    const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>();
    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    this->emitUniforms(uniformHandler, ge);
    fTBiasScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType,
                                                kDefault_GrSLPrecision, "SweepFSParams");
    const char* tBiasScaleV = uniformHandler->getUniformCStr(fTBiasScaleUni);

    const SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);

    // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is
    // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in
    // (sqrt(x^2 + y^2) + x) as the second parameter to atan2 in these cases. We let the device
    // handle the undefined behavior of the second paramenter being 0 instead of doing the
    // divide ourselves and using atan instead.
    const SkString atan = args.fShaderCaps->atan2ImplementedAsAtanYOverX()
        ? SkStringPrintf("2.0 * atan(- %s.y, length(%s) - %s.x)",
                         coords2D.c_str(), coords2D.c_str(), coords2D.c_str())
        : SkStringPrintf("atan(- %s.y, - %s.x)", coords2D.c_str(), coords2D.c_str());

    // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
    const SkString t = SkStringPrintf("((%s * 0.1591549430918 + 0.5 + %s[0]) * %s[1])",
                                      atan.c_str(), tBiasScaleV, tBiasScaleV);

    this->emitColor(args.fFragBuilder,
                    args.fUniformHandler,
                    args.fShaderCaps,
                    ge, t.c_str(),
                    args.fOutputColor,
                    args.fInputColor,
                    args.fTexSamplers);
}

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

sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs& args) const {

    SkMatrix matrix;
    if (!this->getLocalMatrix().invert(&matrix)) {
        return nullptr;
    }
    if (args.fLocalMatrix) {
        SkMatrix inv;
        if (!args.fLocalMatrix->invert(&inv)) {
            return nullptr;
        }
        matrix.postConcat(inv);
    }
    matrix.postConcat(fPtsToUnit);

    sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
                                                                       args.fDstColorSpace);
    sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make(
        GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
                                     std::move(colorSpaceXform), SkToBool(args.fDstColorSpace)),
                                     fTBias, fTScale));
    if (!inner) {
        return nullptr;
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
}

#endif

sk_sp<SkShader> SkSweepGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    SkSTArray<8, SkColor> xformedColors(fColorCount);
    xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);
    return SkGradientShader::MakeSweep(fCenter.fX, fCenter.fY, xformedColors.begin(), fOrigPos,
                                       fColorCount, fGradFlags, &this->getLocalMatrix());
}

#ifndef SK_IGNORE_TO_STRING
void SkSweepGradient::toString(SkString* str) const {
    str->append("SkSweepGradient: (");

    str->append("center: (");
    str->appendScalar(fCenter.fX);
    str->append(", ");
    str->appendScalar(fCenter.fY);
    str->append(") ");

    this->INHERITED::toString(str);

    str->append(")");
}

void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p,
                                           SkRasterPipeline*) const {
    p->append(SkRasterPipeline::xy_to_unit_angle);
    p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeScale(fTScale, 1),
                                             SkMatrix::MakeTrans(fTBias , 0)));
}

#endif
<commit_msg>Fix sweep gradient tiling w/ makeColorSpace<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpaceXformer.h"
#include "SkSweepGradient.h"

#include "SkPM4fPriv.h"
#include "SkRasterPipeline.h"

SkSweepGradient::SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1,
                                 const Descriptor& desc)
    : SkGradientShaderBase(desc, SkMatrix::MakeTrans(-center.x(), -center.y()))
    , fCenter(center)
    , fTBias(-t0)
    , fTScale(1 / (t1 - t0))
{
    SkASSERT(t0 < t1);
}

SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const {
    if (info) {
        commonAsAGradient(info);
        info->fPoint[0] = fCenter;
    }
    return kSweep_GradientType;
}

static std::tuple<SkScalar, SkScalar> angles_from_t_coeff(SkScalar tBias, SkScalar tScale) {
    return std::make_tuple(-tBias * 360, (1 / tScale - tBias) * 360);
}

sk_sp<SkFlattenable> SkSweepGradient::CreateProc(SkReadBuffer& buffer) {
    DescriptorScope desc;
    if (!desc.unflatten(buffer)) {
        return nullptr;
    }
    const SkPoint center = buffer.readPoint();

    SkScalar startAngle = 0,
               endAngle = 360;
    if (!buffer.isVersionLT(SkReadBuffer::kTileInfoInSweepGradient_Version)) {
        const auto tBias  = buffer.readScalar(),
                   tScale = buffer.readScalar();
        std::tie(startAngle, endAngle) = angles_from_t_coeff(tBias, tScale);
    }

    return SkGradientShader::MakeSweep(center.x(), center.y(), desc.fColors,
                                       std::move(desc.fColorSpace), desc.fPos, desc.fCount,
                                       desc.fTileMode, startAngle, endAngle,
                                       desc.fGradFlags, desc.fLocalMatrix);
}

void SkSweepGradient::flatten(SkWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writePoint(fCenter);
    buffer.writeScalar(fTBias);
    buffer.writeScalar(fTScale);
}

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

#if SK_SUPPORT_GPU

#include "SkGr.h"
#include "GrShaderCaps.h"
#include "gl/GrGLContext.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"

class GrSweepGradient : public GrGradientEffect {
public:
    class GLSLSweepProcessor;

    static sk_sp<GrFragmentProcessor> Make(const CreateArgs& args, SkScalar tBias,
                                           SkScalar tScale) {
        auto processor = sk_sp<GrSweepGradient>(new GrSweepGradient(args, tBias, tScale));
        return processor->isValid() ? std::move(processor) : nullptr;
    }

    const char* name() const override { return "Sweep Gradient"; }

    sk_sp<GrFragmentProcessor> clone() const override {
        return sk_sp<GrFragmentProcessor>(new GrSweepGradient(*this));
    }

private:
    explicit GrSweepGradient(const CreateArgs& args, SkScalar tBias, SkScalar tScale)
            : INHERITED(args, args.fShader->colorsAreOpaque())
            , fTBias(tBias)
            , fTScale(tScale){
        this->initClassID<GrSweepGradient>();
    }

    explicit GrSweepGradient(const GrSweepGradient& that)
            : INHERITED(that)
            , fTBias(that.fTBias)
            , fTScale(that.fTScale) {
        this->initClassID<GrSweepGradient>();
    }

    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;

    virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                       GrProcessorKeyBuilder* b) const override;

     bool onIsEqual(const GrFragmentProcessor& base) const override {
         const GrSweepGradient& fp = base.cast<GrSweepGradient>();
         return INHERITED::onIsEqual(base)
             && fTBias == fp.fTBias
             && fTScale == fp.fTScale;
     }

    GR_DECLARE_FRAGMENT_PROCESSOR_TEST

    SkScalar fTBias;
    SkScalar fTScale;

    typedef GrGradientEffect INHERITED;
};

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

class GrSweepGradient::GLSLSweepProcessor : public GrGradientEffect::GLSLProcessor {
public:
    GLSLSweepProcessor(const GrProcessor&)
        : fCachedTBias(SK_FloatNaN)
        , fCachedTScale(SK_FloatNaN) {}

    void emitCode(EmitArgs&) override;

    static void GenKey(const GrProcessor& processor, const GrShaderCaps&,
                       GrProcessorKeyBuilder* b) {
        b->add32(GenBaseGradientKey(processor));
    }

protected:
    void onSetData(const GrGLSLProgramDataManager& pdman,
                   const GrFragmentProcessor& processor) override {
        INHERITED::onSetData(pdman, processor);
        const GrSweepGradient& data = processor.cast<GrSweepGradient>();

        if (fCachedTBias != data.fTBias || fCachedTScale != data.fTScale) {
            fCachedTBias  = data.fTBias;
            fCachedTScale = data.fTScale;
            pdman.set2f(fTBiasScaleUni, fCachedTBias, fCachedTScale);
        }
    }

private:
    UniformHandle fTBiasScaleUni;

    // Uploaded uniform values.
    float fCachedTBias,
          fCachedTScale;

    typedef GrGradientEffect::GLSLProcessor INHERITED;
};

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

GrGLSLFragmentProcessor* GrSweepGradient::onCreateGLSLInstance() const {
    return new GrSweepGradient::GLSLSweepProcessor(*this);
}

void GrSweepGradient::onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                            GrProcessorKeyBuilder* b) const {
    GrSweepGradient::GLSLSweepProcessor::GenKey(*this, caps, b);
}

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

GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSweepGradient);

#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrSweepGradient::TestCreate(GrProcessorTestData* d) {
    SkPoint center = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};

    RandomGradientParams params(d->fRandom);
    auto shader = params.fUseColors4f ?
        SkGradientShader::MakeSweep(center.fX, center.fY, params.fColors4f, params.fColorSpace,
                                    params.fStops, params.fColorCount) :
        SkGradientShader::MakeSweep(center.fX, center.fY,  params.fColors,
                                    params.fStops, params.fColorCount);
    GrTest::TestAsFPArgs asFPArgs(d);
    sk_sp<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args());
    GrAlwaysAssert(fp);
    return fp;
}
#endif

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

void GrSweepGradient::GLSLSweepProcessor::emitCode(EmitArgs& args) {
    const GrSweepGradient& ge = args.fFp.cast<GrSweepGradient>();
    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    this->emitUniforms(uniformHandler, ge);
    fTBiasScaleUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec2f_GrSLType,
                                                kDefault_GrSLPrecision, "SweepFSParams");
    const char* tBiasScaleV = uniformHandler->getUniformCStr(fTBiasScaleUni);

    const SkString coords2D = args.fFragBuilder->ensureCoords2D(args.fTransformedCoords[0]);

    // On some devices they incorrectly implement atan2(y,x) as atan(y/x). In actuality it is
    // atan2(y,x) = 2 * atan(y / (sqrt(x^2 + y^2) + x)). So to work around this we pass in
    // (sqrt(x^2 + y^2) + x) as the second parameter to atan2 in these cases. We let the device
    // handle the undefined behavior of the second paramenter being 0 instead of doing the
    // divide ourselves and using atan instead.
    const SkString atan = args.fShaderCaps->atan2ImplementedAsAtanYOverX()
        ? SkStringPrintf("2.0 * atan(- %s.y, length(%s) - %s.x)",
                         coords2D.c_str(), coords2D.c_str(), coords2D.c_str())
        : SkStringPrintf("atan(- %s.y, - %s.x)", coords2D.c_str(), coords2D.c_str());

    // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
    const SkString t = SkStringPrintf("((%s * 0.1591549430918 + 0.5 + %s[0]) * %s[1])",
                                      atan.c_str(), tBiasScaleV, tBiasScaleV);

    this->emitColor(args.fFragBuilder,
                    args.fUniformHandler,
                    args.fShaderCaps,
                    ge, t.c_str(),
                    args.fOutputColor,
                    args.fInputColor,
                    args.fTexSamplers);
}

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

sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs& args) const {

    SkMatrix matrix;
    if (!this->getLocalMatrix().invert(&matrix)) {
        return nullptr;
    }
    if (args.fLocalMatrix) {
        SkMatrix inv;
        if (!args.fLocalMatrix->invert(&inv)) {
            return nullptr;
        }
        matrix.postConcat(inv);
    }
    matrix.postConcat(fPtsToUnit);

    sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
                                                                       args.fDstColorSpace);
    sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make(
        GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
                                     std::move(colorSpaceXform), SkToBool(args.fDstColorSpace)),
                                     fTBias, fTScale));
    if (!inner) {
        return nullptr;
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
}

#endif

sk_sp<SkShader> SkSweepGradient::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
    SkSTArray<8, SkColor> xformedColors(fColorCount);
    xformer->apply(xformedColors.begin(), fOrigColors, fColorCount);

    SkScalar startAngle, endAngle;
    std::tie(startAngle, endAngle) = angles_from_t_coeff(fTBias, fTScale);

    return SkGradientShader::MakeSweep(fCenter.fX, fCenter.fY, xformedColors.begin(), fOrigPos,
                                       fColorCount, fTileMode, startAngle, endAngle,
                                       fGradFlags, &this->getLocalMatrix());
}

#ifndef SK_IGNORE_TO_STRING
void SkSweepGradient::toString(SkString* str) const {
    str->append("SkSweepGradient: (");

    str->append("center: (");
    str->appendScalar(fCenter.fX);
    str->append(", ");
    str->appendScalar(fCenter.fY);
    str->append(") ");

    this->INHERITED::toString(str);

    str->append(")");
}

void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p,
                                           SkRasterPipeline*) const {
    p->append(SkRasterPipeline::xy_to_unit_angle);
    p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeScale(fTScale, 1),
                                             SkMatrix::MakeTrans(fTBias , 0)));
}

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2008, 2009 by Florent Lamiraux, Thomas Moulard, CNRS.
//
// This file is part of the hpp-util.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//
// See the COPYING file for more information.

#ifndef HPP_UTIL_DEBUG_HH
# define HPP_UTIL_DEBUG_HH
# include <cstdlib>
# include <ostream>
# include <fstream>
# include <sstream>
# include <vector>

# include <hpp/util/config.hh>
# include <hpp/util/indent.hh>

namespace hpp
{
  namespace debug
  {
    class Output;
    class JournalOutput;
    class ConsoleOutput;

    class Channel;
  } // end of namespace debug
} // end of namespace hpp.

namespace hpp
{
  namespace debug
  {
    /// \brief Compute the logging prefix.
    ///
    /// This method returns the logging prefix. It means the
    /// directory where all debugging output must be stored.
    ///
    /// The prefix is $localstatedir/log/$packagename.
    ///
    /// \li localstatedir: [prefix]/var (by
    /// default /usr/local/var)
    /// \lipackagename: this function's first argument
    ///
    /// To use this function, first include config.h and
    /// use the PACKAGE_TARNAME provided by Autoheader as
    /// this function's first argument.
    ///
    /// The prefix $localstatedir/log can be overrided by
    /// the environment variable HPP_LOGGINGDIR.
    ///
    ///
    /// \param packageName name of the package, must be a valid Unix
    /// filename (the use of PACKAGE_TARNAME is strongly
    /// encouraged).
    HPP_UTIL_DLLAPI std::string getPrefix (const std::string& packageName);

    /// \brief Compute the path of a file in the logging prefix.
    ///
    /// Apply the same rules than getPrefix and append the filename
    /// to build the whole path.
    ///
    /// \param filename Name of the file (will be appended to the prefix)
    /// \param packageName name of the package, must be a valid Unix
    /// filename (the use of PACKAGE_TARNAME is strongly
    /// encouraged).
    HPP_UTIL_DLLAPI std::string getFilename (const std::string& filename,
					const std::string& packageName);

    /// \brief Debugging output.
    ///
    /// Represents a debugging output, i.e. an output stream
    /// which can subscribe to channels.
    ///
    /// There is two default output:
    /// \li console which points to std::cerr
    /// \li journal which points to the ``journal'' file in the
    /// debugging prefix
    class HPP_UTIL_DLLAPI Output
    {
    public:
      explicit Output ();
      virtual ~Output ();

      virtual void
	write (const Channel& channel,
	       char const* file,
	       int line,
	       char const* function,
	       const std::string& data) = 0;

    protected:
      std::ostream&
	writePrefix (std::ostream& stream,
		     const Channel& channel,
		     char const* file,
		     int line,
		     char const* function);
    };

    /// \brief Receive debugging information.
    ///
    /// Receive debugging information and forward it to its
    /// subscribers.
    ///
    /// By default, there is four channels:
    /// - error for fatal problems
    /// - warning for non-fatal problems
    /// - notice for user information
    /// - info for technical information and debugging output
    class HPP_UTIL_DLLAPI Channel
    {
    public:
      typedef std::vector<Output*> subscribers_t;

      explicit Channel (char const* label,
			const subscribers_t& subscribers);
      virtual ~Channel ();

      void write (char const* file,
		  int line,
		  char const* function,
		  const std::string& data);

      const char* label () const;
    private:
      const char* label_;
      subscribers_t subscribers_;
    };

    /// \brief Logging in journal file in the logging directory.
    class HPP_UTIL_DLLAPI JournalOutput : public Output
    {
    public:
      explicit JournalOutput (std::string filename);
      ~JournalOutput ();

      void write (const Channel& channel,
		  char const* file,
		  int line,
		  char const* function,
		  const std::string& data);

      std::string getFilename () const;

    private:
      std::string filename;
      std::string lastFunction;
      std::ofstream stream;
    };

    /// \brief Logging in console (std::cerr).
    class HPP_UTIL_DLLAPI ConsoleOutput : public Output
    {
    public:
      explicit ConsoleOutput ();
      ~ConsoleOutput ();
      void write (const Channel& channel,
		  char const* file,
		  int line,
		  char const* function,
		  const std::string& data);
    };

    /// \brief Logging class owns all channels and outputs.
    class HPP_UTIL_DLLAPI Logging
    {
    public:
      explicit Logging ();
      ~Logging ();

      /// \brief Logs to console (i.e. stderr).
      ConsoleOutput console;
      /// \brief Logs to main journal file (i.e. journal.XXX.log).
      JournalOutput journal;
      /// \brief Logs to benchmark journal file (i.e. benchmark.XXX.log).
      JournalOutput benchmarkJournal;

      /// \brief Fatal problems channel.
      Channel error;

      /// \brief Non-fatal problems channel.
      Channel warning;

      /// \brief User-oriented information.
      Channel notice;

      /// \brief Technical information and debugging.
      Channel info;

      /// \brief Benchmark information.
      Channel benchmark;
    };
  } // end of namespace debug
} // end of namespace hpp.

namespace hpp
{
  namespace debug
  {
    /// \brief Benchmark information.
    extern HPP_UTIL_DLLAPI Logging logging;
  } // end of namespace debug
} // end of namespace hpp

# ifdef HPP_DEBUG

#  define hppDebug(statement)			\
  do {						\
    using namespace ::hpp::debug;		\
    { statement; }				\
  } while(0)

#  define hppDebugStatement(statement)		\
  statement

#  define hppDout(channel, data)					\
  do {									\
    using namespace hpp;						\
    using namespace ::hpp::debug;					\
    std::stringstream __ss;						\
    __ss << data << iendl;						\
    logging.channel.write (__FILE__, __LINE__, __PRETTY_FUNCTION__,     \
			   __ss.str ());				\
  } while (0)

#  define hppDoutFatal(channel, data)					\
  do {									\
    using namespace hpp;						\
    using namespace ::hpp::debug;					\
    std::stringstream __ss;						\
    __ss << data << iendl;						\
    logging.channel.write ( __FILE__, __LINE__,	__PRETTY_FUNCTION__,	\
			    __ss.str ());				\
    ::std::exit(EXIT_FAILURE);						\
  } while (1)

# else

#  define hppDebug(statement)
#  define hppDebugStatement(statement)
#  define hppDout(channel, data)
#  define hppDoutFatal(channel, data)		\
  do {						\
    using namespace hpp;			\
    ::std::cerr << data << iendl;		\
    ::std::exit (EXIT_FAILURE);			\
  } while (1)

# endif // HPP_DEBUG

#endif //! HPP_UTIL_DEBUG_HH
<commit_msg>Add empty body to logging signals when HPP_DEBUG is undefined.<commit_after>// Copyright (C) 2008, 2009 by Florent Lamiraux, Thomas Moulard, CNRS.
//
// This file is part of the hpp-util.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//
// See the COPYING file for more information.

#ifndef HPP_UTIL_DEBUG_HH
# define HPP_UTIL_DEBUG_HH
# include <cstdlib>
# include <ostream>
# include <fstream>
# include <sstream>
# include <vector>

# include <hpp/util/config.hh>
# include <hpp/util/indent.hh>

namespace hpp
{
  namespace debug
  {
    class Output;
    class JournalOutput;
    class ConsoleOutput;

    class Channel;
  } // end of namespace debug
} // end of namespace hpp.

namespace hpp
{
  namespace debug
  {
    /// \brief Compute the logging prefix.
    ///
    /// This method returns the logging prefix. It means the
    /// directory where all debugging output must be stored.
    ///
    /// The prefix is $localstatedir/log/$packagename.
    ///
    /// \li localstatedir: [prefix]/var (by
    /// default /usr/local/var)
    /// \lipackagename: this function's first argument
    ///
    /// To use this function, first include config.h and
    /// use the PACKAGE_TARNAME provided by Autoheader as
    /// this function's first argument.
    ///
    /// The prefix $localstatedir/log can be overrided by
    /// the environment variable HPP_LOGGINGDIR.
    ///
    ///
    /// \param packageName name of the package, must be a valid Unix
    /// filename (the use of PACKAGE_TARNAME is strongly
    /// encouraged).
    HPP_UTIL_DLLAPI std::string getPrefix (const std::string& packageName);

    /// \brief Compute the path of a file in the logging prefix.
    ///
    /// Apply the same rules than getPrefix and append the filename
    /// to build the whole path.
    ///
    /// \param filename Name of the file (will be appended to the prefix)
    /// \param packageName name of the package, must be a valid Unix
    /// filename (the use of PACKAGE_TARNAME is strongly
    /// encouraged).
    HPP_UTIL_DLLAPI std::string getFilename (const std::string& filename,
					const std::string& packageName);

    /// \brief Debugging output.
    ///
    /// Represents a debugging output, i.e. an output stream
    /// which can subscribe to channels.
    ///
    /// There is two default output:
    /// \li console which points to std::cerr
    /// \li journal which points to the ``journal'' file in the
    /// debugging prefix
    class HPP_UTIL_DLLAPI Output
    {
    public:
      explicit Output ();
      virtual ~Output ();

      virtual void
	write (const Channel& channel,
	       char const* file,
	       int line,
	       char const* function,
	       const std::string& data) = 0;

    protected:
      std::ostream&
	writePrefix (std::ostream& stream,
		     const Channel& channel,
		     char const* file,
		     int line,
		     char const* function);
    };

    /// \brief Receive debugging information.
    ///
    /// Receive debugging information and forward it to its
    /// subscribers.
    ///
    /// By default, there is four channels:
    /// - error for fatal problems
    /// - warning for non-fatal problems
    /// - notice for user information
    /// - info for technical information and debugging output
    class HPP_UTIL_DLLAPI Channel
    {
    public:
      typedef std::vector<Output*> subscribers_t;

      explicit Channel (char const* label,
			const subscribers_t& subscribers);
      virtual ~Channel ();

      void write (char const* file,
		  int line,
		  char const* function,
		  const std::string& data);

      const char* label () const;
    private:
      const char* label_;
      subscribers_t subscribers_;
    };

    /// \brief Logging in journal file in the logging directory.
    class HPP_UTIL_DLLAPI JournalOutput : public Output
    {
    public:
      explicit JournalOutput (std::string filename);
      ~JournalOutput ();

      void write (const Channel& channel,
		  char const* file,
		  int line,
		  char const* function,
		  const std::string& data);

      std::string getFilename () const;

    private:
      std::string filename;
      std::string lastFunction;
      std::ofstream stream;
    };

    /// \brief Logging in console (std::cerr).
    class HPP_UTIL_DLLAPI ConsoleOutput : public Output
    {
    public:
      explicit ConsoleOutput ();
      ~ConsoleOutput ();
      void write (const Channel& channel,
		  char const* file,
		  int line,
		  char const* function,
		  const std::string& data);
    };

    /// \brief Logging class owns all channels and outputs.
    class HPP_UTIL_DLLAPI Logging
    {
    public:
      explicit Logging ();
      ~Logging ();

      /// \brief Logs to console (i.e. stderr).
      ConsoleOutput console;
      /// \brief Logs to main journal file (i.e. journal.XXX.log).
      JournalOutput journal;
      /// \brief Logs to benchmark journal file (i.e. benchmark.XXX.log).
      JournalOutput benchmarkJournal;

      /// \brief Fatal problems channel.
      Channel error;

      /// \brief Non-fatal problems channel.
      Channel warning;

      /// \brief User-oriented information.
      Channel notice;

      /// \brief Technical information and debugging.
      Channel info;

      /// \brief Benchmark information.
      Channel benchmark;
    };
  } // end of namespace debug
} // end of namespace hpp.

namespace hpp
{
  namespace debug
  {
    /// \brief Benchmark information.
    extern HPP_UTIL_DLLAPI Logging logging;
  } // end of namespace debug
} // end of namespace hpp

# ifdef HPP_DEBUG

#  define hppDebug(statement)			\
  do {						\
    using namespace ::hpp::debug;		\
    { statement; }				\
  } while(0)

#  define hppDebugStatement(statement)		\
  statement

#  define hppDout(channel, data)					\
  do {									\
    using namespace hpp;						\
    using namespace ::hpp::debug;					\
    std::stringstream __ss;						\
    __ss << data << iendl;						\
    logging.channel.write (__FILE__, __LINE__, __PRETTY_FUNCTION__,     \
			   __ss.str ());				\
  } while (0)

#  define hppDoutFatal(channel, data)					\
  do {									\
    using namespace hpp;						\
    using namespace ::hpp::debug;					\
    std::stringstream __ss;						\
    __ss << data << iendl;						\
    logging.channel.write ( __FILE__, __LINE__,	__PRETTY_FUNCTION__,	\
			    __ss.str ());				\
    ::std::exit(EXIT_FAILURE);						\
  } while (1)

# else

#  define hppDebug(statement)			\
  do {                                          \
  } while (0)
#  define hppDebugStatement(statement)          \
  do {                                          \
  } while (0)
#  define hppDout(channel, data)                \
  do {                                          \
  } while (0)
#  define hppDoutFatal(channel, data)		\
  do {						\
    using namespace hpp;			\
    ::std::cerr << data << iendl;		\
    ::std::exit (EXIT_FAILURE);			\
  } while (1)

# endif // HPP_DEBUG

#endif //! HPP_UTIL_DEBUG_HH
<|endoftext|>