<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::noncopyable and compiler-specific STL type_traits fixes

namespace abc {

//! Makes a derived class not copyable.
class noncopyable {
protected:
   //! Constructor. Protected to prevent instantiations of this class as-is.
   noncopyable() {
   }

   //! Destructor. Protected to deter using this class as a polymorphic base.
   ~noncopyable() {
   }

#ifdef ABC_CXX_FUNC_DELETE
   noncopyable(noncopyable const &) = delete;
   noncopyable & operator=(noncopyable const &) = delete;
#else //ifdef ABC_CXX_FUNC_DELETE
private:
   noncopyable(noncopyable const &);
   noncopyable & operator=(noncopyable const &);
#endif //ifdef ABC_CXX_FUNC_DELETE … else
};

} //namespace abc

#ifdef ABC_STLIMPL
   #include <abaclade/_std/type_traits.hxx>
#else
   #if ABC_HOST_CXX_MSC == 1800
      /*! DOC:1082 std::is_copy_constructible MSC18 bugs

      With VS2013, Microsoft introduced a completely broken std::is_copy_constructible that makes
      one wish they didn’t: it returns true for classes with private copy constructors[1], classes
      with deleted constructors[2], and classes composed by non-copyable classes[2].
      [1] <https://connect.microsoft.com/VisualStudio/feedback/details/799732/is-copy-constructible-
         always-returns-true-for-private-copy-constructors>
      [2] <https://connect.microsoft.com/VisualStudio/feedback/details/800328/std-is-copy-
         constructible-is-broken>

      The only way of fixing it for both Abaclade without breaking MSC’s STL implementation is to
      override to enhance it with Abaclade’s version, making the latter fall back to MSC’s broken
      implementation. In the worst case, this might make it report classes as non-copyable when they
      are, but it will (hopefully) not report non-copyable classes as copyable. */
      #define is_copy_constructible _ABC_MSC18_is_copy_constructible
   #endif
   #include <type_traits>
   #if ABC_HOST_CXX_MSC == 1800
      #undef is_copy_constructible
   #endif
#endif

#if ( \
   (ABC_HOST_CXX_GCC && ABC_HOST_CXX_GCC < 40700) || (ABC_HOST_CXX_MSC && ABC_HOST_CXX_MSC < 1900) \
) && !defined(ABC_STLIMPL)

namespace std {

#if ABC_HOST_CXX_GCC
   // GCC lacks a definition of std::add_reference.
   template <typename T>
   struct add_reference {
      typedef T & type;
   };
   template <typename T>
   struct add_reference<T &> {
      typedef T & type;
   };
#elif ABC_HOST_CXX_MSC < 1800
   // MSC16 lacks a definition of std::declval.
   template <typename T>
   typename add_rvalue_reference<T>::type declval();
#endif

template <typename T, typename = void>
struct is_copy_constructible {
private:
   static int test(T &);
   static char test(...);

   typedef typename add_reference<T>::type TRef;

public:
   static bool const value = (sizeof(test(declval<TRef>())) == sizeof(int))
#if ABC_HOST_CXX_MSC == 1800
      /* MSC18 does provide an implementation which, while severely flawed (see [DOC:1082
      std::is_copy_constructible MSC18 bugs]), may be stricter than this, so && its return value. */
      && _ABC_MSC18_is_copy_constructible<T>::value
#endif
   ;
};

template <typename T>
struct is_copy_constructible<T, typename enable_if<
   is_base_of< ::abc::noncopyable, T>::value
>::type> : public false_type {};

#define ABC_STLIMPL_IS_COPY_CONSTRUCTIBLE

} //namespace std

#endif //if ((ABC_HOST_CXX_GCC && ABC_HOST_CXX_GCC < 40700) ||
       //   (ABC_HOST_CXX_MSC && ABC_HOST_CXX_MSC < 1900) && !defined(ABC_STLIMPL)

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Improve code documentation<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::noncopyable and compiler-specific STL type_traits fixes

namespace abc {

/*! Makes a derived class not copyable.

Derive a class from this for maximum compatibility instead of explicitly deleting copy constructor
and copy assignment operator. */
class noncopyable {
protected:
   //! Constructor. Protected to prevent instantiations of this class as-is.
   noncopyable() {
   }

   //! Destructor. Protected to deter using this class as a polymorphic base.
   ~noncopyable() {
   }

#ifdef ABC_CXX_FUNC_DELETE
   noncopyable(noncopyable const &) = delete;
   noncopyable & operator=(noncopyable const &) = delete;
#else
private:
   noncopyable(noncopyable const &);
   noncopyable & operator=(noncopyable const &);
#endif
};

} //namespace abc

#ifdef ABC_STLIMPL
   #include <abaclade/_std/type_traits.hxx>
#else
   #if ABC_HOST_CXX_MSC == 1800
      /*! DOC:1082 std::is_copy_constructible MSC18 bugs

      With VS2013, Microsoft introduced a completely broken std::is_copy_constructible that makes
      one wish they didn’t: it returns true for classes with private copy constructors[1], classes
      with deleted constructors[2], and classes composed by non-copyable classes[2].
      [1] <https://connect.microsoft.com/VisualStudio/feedback/details/799732/is-copy-constructible-
         always-returns-true-for-private-copy-constructors>
      [2] <https://connect.microsoft.com/VisualStudio/feedback/details/800328/std-is-copy-
         constructible-is-broken>

      The only way of fixing it for both Abaclade without breaking MSC’s STL implementation is to
      override to enhance it with Abaclade’s version, making the latter fall back to MSC’s broken
      implementation. In the worst case, this might make it report classes as non-copyable when they
      are, but it will (hopefully) not report non-copyable classes as copyable. */
      #define is_copy_constructible _ABC_MSC18_is_copy_constructible
   #endif
   #include <type_traits>
   #if ABC_HOST_CXX_MSC == 1800
      #undef is_copy_constructible
   #endif
#endif

#if ( \
   (ABC_HOST_CXX_GCC && ABC_HOST_CXX_GCC < 40700) || (ABC_HOST_CXX_MSC && ABC_HOST_CXX_MSC < 1900) \
) && !defined(ABC_STLIMPL)

namespace std {

#if ABC_HOST_CXX_GCC
   // GCC lacks a definition of std::add_reference.
   template <typename T>
   struct add_reference {
      typedef T & type;
   };
   template <typename T>
   struct add_reference<T &> {
      typedef T & type;
   };
#elif ABC_HOST_CXX_MSC < 1800
   // MSC16 lacks a definition of std::declval.
   template <typename T>
   typename add_rvalue_reference<T>::type declval();
#endif

template <typename T, typename = void>
struct is_copy_constructible {
private:
   static int test(T &);
   static char test(...);

   typedef typename add_reference<T>::type TRef;

public:
   static bool const value = (sizeof(test(declval<TRef>())) == sizeof(int))
#if ABC_HOST_CXX_MSC == 1800
      /* MSC18 does provide an implementation which, while severely flawed (see [DOC:1082
      std::is_copy_constructible MSC18 bugs]), may be stricter than this, so && its return value. */
      && _ABC_MSC18_is_copy_constructible<T>::value
#endif
   ;
};

template <typename T>
struct is_copy_constructible<T, typename enable_if<
   is_base_of< ::abc::noncopyable, T>::value
>::type> : public false_type {};

#define ABC_STLIMPL_IS_COPY_CONSTRUCTIBLE

} //namespace std

#endif //if ((ABC_HOST_CXX_GCC && ABC_HOST_CXX_GCC < 40700) ||
       //   (ABC_HOST_CXX_MSC && ABC_HOST_CXX_MSC < 1900) && !defined(ABC_STLIMPL)

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>// Part of the apollo library -- Copyright (c) Christian Neumüller 2015
// This file is subject to the terms of the BSD 2-Clause License.
// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause

#ifndef APOLLO_BUILTIN_TYPES_HPP_INCLUDED
#define APOLLO_BUILTIN_TYPES_HPP_INCLUDED APOLLO_BUILTIN_TYPES_HPP_INCLUDED

#include <apollo/config.hpp>
#include <apollo/converters.hpp>

#include <boost/assert.hpp>

#include <limits>
#include <string>

namespace apollo {

// Number converter //
template<typename T>
struct converter<T, typename std::enable_if<
        !std::is_enum<T>::value
        && detail::lua_type_id<T>::value == LUA_TNUMBER>::type
    >: converter_base<T> {
private:
    using llimits = std::numeric_limits<lua_Integer>;
    static bool const is_integral = std::is_integral<T>::value;
    static bool const is_safe_integral = is_integral &&
        sizeof(T) <= sizeof(lua_Integer) &&
        std::is_signed<T>::value == std::is_signed<lua_Integer>::value;

public:
    static int push(lua_State* L, T n)
    {
#ifdef BOOST_MSVC
#   pragma warning(push)
#   pragma warning(disable:4127) // Conditional expression is constant.
#endif
        if (is_integral && (is_safe_integral
#if LUA_VERSION_NUM >= 503 // Not worth the effort on < 5.3.
            || (n >= llimits::min() && n <= llimits::max())
#endif // LUA_VERSION_NUM >= 503
        )) {
#ifdef BOOST_MSVC
#   pragma warning(pop)
#endif
            lua_pushinteger(L, static_cast<lua_Integer>(n));
        } else {
            lua_pushnumber(L, static_cast<lua_Number>(n));
        }
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        if (lua_type(L, idx) == LUA_TNUMBER) { // Actual number.
#if LUA_VERSION_NUM >= 503
            if ((lua_isinteger(L, idx) ? true : false) == is_integral)
                return 0;
            return 1;
#else // LUA_VERSION_NUM >= 503
            return 0;
#endif // LUA_VERSION_NUM >= 503 / else
        }
        if (lua_isnumber(L, idx)) // String convertible to number.
            return 2;
        return no_conversion;
    }

    static T to(lua_State* L, int idx)
    {
#if LUA_VERSION_NUM >= 503
#   ifdef BOOST_MSVC
#       pragma warning(push)
#       pragma warning(disable:4127) // Conditional expression is constant.
#   endif
        if (is_integral && lua_isinteger(L, idx))
            return static_cast<T>(lua_tointeger(L, idx));
#   ifdef BOOST_MSVC
#       pragma warning(pop)
#   endif
#endif
        return static_cast<T>(lua_tonumber(L, idx));
    }
};

// Enum converter //
template<typename T>
struct converter<T,
        typename std::enable_if<std::is_enum<T>::value>::type
    >: converter_base<T> {

    static int push(lua_State* L, T n)
    {
        lua_pushinteger(L, static_cast<lua_Integer>(n));
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        if (lua_type(L, idx) == LUA_TNUMBER)
            return 1;
        return no_conversion;
    }

    static T to(lua_State* L, int idx)
    {
        return static_cast<T>(lua_tointeger(L, idx));
    }
};

// Boolean converter //
template<>
struct converter<bool>: converter_base<bool> {

    static int push(lua_State* L, bool b)
    {
        lua_pushboolean(L, static_cast<int>(b));
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        // Convert non-boolean values to bool only as a last resort.
        return lua_isboolean(L, idx) ? 0 : no_conversion - 1;
    }

    static bool to(lua_State* L, int idx)
    {
        // Avoid MSVC "performance warning" about int to bool conversion with
        // ternary operator.
        return lua_toboolean(L, idx) ? true : false;
    }
};

// void converter //
template<>
struct converter<void>: converter_base<void> {
    static unsigned n_conversion_steps(lua_State*, int)
    {
        return no_conversion - 1;
    }

    static void to(lua_State*, int)
    { }
};

// String converter //

namespace detail {

inline void push_string(lua_State* L, char c)
{
    lua_pushlstring(L, &c, 1);
}

template <std::size_t N>
void push_string(lua_State* L, char const (&s)[N])
{
    // Don't count null termination.
    lua_pushlstring(L, s, N - (s[N - 1] == 0));
}

// Need to make this a template too, so that the array overload is called in
// the appropriate cases. Also can't make it const T* because otherwise the
// call would be ambigous.
template <typename T>
inline void push_string(lua_State* L, T s)
{
    using T2 = typename remove_qualifiers<T>::type;
    static_assert(
        std::is_same<T2, char*>::value || std::is_same<T2, char const*>::value,
        "push_string called with non-string");
    lua_pushstring(L, s);
}

inline void push_string(lua_State* L, std::string const& s)
{
    lua_pushlstring(L, s.c_str(), s.size());
}

template <typename T>
struct to_string { // char*, char const*, char[N]
    using type = char const*;
    static type to(lua_State* L, int idx)
    {
        return lua_tostring(L, idx);
    }
};

template <>
struct to_string<std::string> {
    using type = std::string;
    static type to(lua_State* L, int idx)
    {
        std::size_t len;
        char const* s = lua_tolstring(L, idx, &len);
        return std::string(s, len);
    }
};

template <>
struct to_string<char> {
    using type = char;
    static type to(lua_State* L, int idx)
    {
        std::size_t len;
        char const* s = lua_tolstring(L, idx, &len);
        BOOST_ASSERT(len == 1);
        return s[0];
    }
};

template <typename>
struct string_conversion_steps {
    static unsigned get(lua_State* L, int idx)
    {
        switch(lua_type(L, idx)) {
        case LUA_TSTRING:
            return 0;
        case LUA_TNUMBER:
            return 1;
        default:
            return no_conversion;
        }
        BOOST_UNREACHABLE_RETURN(no_conversion);
    }
};

template <>
struct APOLLO_API string_conversion_steps<char> {
    static unsigned get(lua_State* L, int idx);
};

} // namespace detail

template <typename T>
struct converter<T, typename std::enable_if<
        detail::lua_type_id<T>::value == LUA_TSTRING>::type>: converter_base<T> {
    using to_type = typename detail::to_string<T>::type;

    static int push(lua_State* L, T const& s)
    {
        detail::push_string(L, s);
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
       return detail::string_conversion_steps<T>::get(L, idx);
    }

    static to_type to(lua_State* L, int idx)
    {
        return detail::to_string<T>::to(L, idx);
    }
};

template <>
struct converter<void*>: converter_base<void*> {
    static int push(lua_State* L, void* p)
    {
        lua_pushlightuserdata(L, p);
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        return lua_islightuserdata(L, idx) ? 0 : no_conversion;
    }

    static void* to(lua_State* L, int idx)
    {
        return lua_touserdata(L, idx);
    }
};

} // namepace apollo

#endif // APOLLO_CONVERTERS_HPP_INCLUDED
<commit_msg>Fix check if number fits in lua_Integer.<commit_after>// Part of the apollo library -- Copyright (c) Christian Neumüller 2015
// This file is subject to the terms of the BSD 2-Clause License.
// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause

#ifndef APOLLO_BUILTIN_TYPES_HPP_INCLUDED
#define APOLLO_BUILTIN_TYPES_HPP_INCLUDED APOLLO_BUILTIN_TYPES_HPP_INCLUDED

#include <apollo/config.hpp>
#include <apollo/converters.hpp>

#include <boost/assert.hpp>

#include <cstdint>
#include <limits>
#include <string>

namespace apollo {

// Number converter //
template<typename T>
struct converter<T, typename std::enable_if<
        !std::is_enum<T>::value
        && detail::lua_type_id<T>::value == LUA_TNUMBER>::type
    >: converter_base<T> {
private:
    static bool const is_integral = std::is_integral<T>::value;
    static bool const is_safe_integral = is_integral &&
        sizeof(T) <= sizeof(lua_Integer) &&
        std::is_signed<T>::value == std::is_signed<lua_Integer>::value;

public:
    static int push(lua_State* L, T n)
    {
#ifdef BOOST_MSVC
#   pragma warning(push)
#   pragma warning(disable:4127) // Conditional expression is constant.
#endif
        if (is_integral && (is_safe_integral
#if LUA_VERSION_NUM >= 503 // Not worth the effort on < 5.3.
            || fits_in_lua_integer(n)
#endif // LUA_VERSION_NUM >= 503
        )) {
#ifdef BOOST_MSVC
#   pragma warning(pop)
#endif
            lua_pushinteger(L, static_cast<lua_Integer>(n));
        } else {
            lua_pushnumber(L, static_cast<lua_Number>(n));
        }
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        if (lua_type(L, idx) == LUA_TNUMBER) { // Actual number.
#if LUA_VERSION_NUM >= 503
            if ((lua_isinteger(L, idx) ? true : false) == is_integral)
                return 0;
            return 1;
#else // LUA_VERSION_NUM >= 503
            return 0;
#endif // LUA_VERSION_NUM >= 503 / else
        }
        if (lua_isnumber(L, idx)) // String convertible to number.
            return 2;
        return no_conversion;
    }

    static T to(lua_State* L, int idx)
    {
#if LUA_VERSION_NUM >= 503
#   ifdef BOOST_MSVC
#       pragma warning(push)
#       pragma warning(disable:4127) // Conditional expression is constant.
#   endif
        if (is_integral && lua_isinteger(L, idx))
            return static_cast<T>(lua_tointeger(L, idx));
#   ifdef BOOST_MSVC
#       pragma warning(pop)
#   endif
#endif
        return static_cast<T>(lua_tonumber(L, idx));
    }

private:
    // Inspired by http://stackoverflow.com/a/17251989.
    static bool fits_in_lua_integer(T n) {
        using llimits = std::numeric_limits<lua_Integer>;
        using tlimits = std::numeric_limits<T>;
        auto const l_lo = static_cast<std::intmax_t>(llimits::min());
        auto const t_lo = static_cast<std::intmax_t>(tlimits::min());
        auto const l_hi = static_cast<std::uintmax_t>(llimits::max());
        auto const t_hi = static_cast<std::uintmax_t>(tlimits::max());
        return (l_lo <= t_lo || n >= static_cast<T>(l_lo))  // Check underflow.
            && (l_hi >= t_hi || n <= static_cast<T>(l_hi)); // Check overflow.
    }
};

// Enum converter //
template<typename T>
struct converter<T,
        typename std::enable_if<std::is_enum<T>::value>::type
    >: converter_base<T> {

    static int push(lua_State* L, T n)
    {
        lua_pushinteger(L, static_cast<lua_Integer>(n));
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        if (lua_type(L, idx) == LUA_TNUMBER)
            return 1;
        return no_conversion;
    }

    static T to(lua_State* L, int idx)
    {
        return static_cast<T>(lua_tointeger(L, idx));
    }
};

// Boolean converter //
template<>
struct converter<bool>: converter_base<bool> {

    static int push(lua_State* L, bool b)
    {
        lua_pushboolean(L, static_cast<int>(b));
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        // Convert non-boolean values to bool only as a last resort.
        return lua_isboolean(L, idx) ? 0 : no_conversion - 1;
    }

    static bool to(lua_State* L, int idx)
    {
        // Avoid MSVC "performance warning" about int to bool conversion with
        // ternary operator.
        return lua_toboolean(L, idx) ? true : false;
    }
};

// void converter //
template<>
struct converter<void>: converter_base<void> {
    static unsigned n_conversion_steps(lua_State*, int)
    {
        return no_conversion - 1;
    }

    static void to(lua_State*, int)
    { }
};

// String converter //

namespace detail {

inline void push_string(lua_State* L, char c)
{
    lua_pushlstring(L, &c, 1);
}

template <std::size_t N>
void push_string(lua_State* L, char const (&s)[N])
{
    // Don't count null termination.
    lua_pushlstring(L, s, N - (s[N - 1] == 0));
}

// Need to make this a template too, so that the array overload is called in
// the appropriate cases. Also can't make it const T* because otherwise the
// call would be ambigous.
template <typename T>
inline void push_string(lua_State* L, T s)
{
    using T2 = typename remove_qualifiers<T>::type;
    static_assert(
        std::is_same<T2, char*>::value || std::is_same<T2, char const*>::value,
        "push_string called with non-string");
    lua_pushstring(L, s);
}

inline void push_string(lua_State* L, std::string const& s)
{
    lua_pushlstring(L, s.c_str(), s.size());
}

template <typename T>
struct to_string { // char*, char const*, char[N]
    using type = char const*;
    static type to(lua_State* L, int idx)
    {
        return lua_tostring(L, idx);
    }
};

template <>
struct to_string<std::string> {
    using type = std::string;
    static type to(lua_State* L, int idx)
    {
        std::size_t len;
        char const* s = lua_tolstring(L, idx, &len);
        return std::string(s, len);
    }
};

template <>
struct to_string<char> {
    using type = char;
    static type to(lua_State* L, int idx)
    {
        std::size_t len;
        char const* s = lua_tolstring(L, idx, &len);
        BOOST_ASSERT(len == 1);
        return s[0];
    }
};

template <typename>
struct string_conversion_steps {
    static unsigned get(lua_State* L, int idx)
    {
        switch(lua_type(L, idx)) {
        case LUA_TSTRING:
            return 0;
        case LUA_TNUMBER:
            return 1;
        default:
            return no_conversion;
        }
        BOOST_UNREACHABLE_RETURN(no_conversion);
    }
};

template <>
struct APOLLO_API string_conversion_steps<char> {
    static unsigned get(lua_State* L, int idx);
};

} // namespace detail

template <typename T>
struct converter<T, typename std::enable_if<
        detail::lua_type_id<T>::value == LUA_TSTRING>::type>: converter_base<T> {
    using to_type = typename detail::to_string<T>::type;

    static int push(lua_State* L, T const& s)
    {
        detail::push_string(L, s);
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
       return detail::string_conversion_steps<T>::get(L, idx);
    }

    static to_type to(lua_State* L, int idx)
    {
        return detail::to_string<T>::to(L, idx);
    }
};

template <>
struct converter<void*>: converter_base<void*> {
    static int push(lua_State* L, void* p)
    {
        lua_pushlightuserdata(L, p);
        return 1;
    }

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        return lua_islightuserdata(L, idx) ? 0 : no_conversion;
    }

    static void* to(lua_State* L, int idx)
    {
        return lua_touserdata(L, idx);
    }
};

} // namepace apollo

#endif // APOLLO_CONVERTERS_HPP_INCLUDED
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Julian Ganz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifndef CMOH_ACCESSOR_BUNDLE_HPP__
#define CMOH_ACCESSOR_BUNDLE_HPP__

// std includes
#include <type_traits>
#include <utility>

// local includes
#include <cmoh/utils.hpp>

namespace cmoh {

/**
 * Accessor bundle
 *
 * Instantiations of this template bundle accessors and make them conveniently
 * accessible as a group, posing as an abstraction layer.
 *
 * TODO: further explanation
 *
 * Users are discouraged from constructing accessor bundles directly. Use
 * `bundle()` instread as a factory.
 */
template <
    typename ...Accessors
>
class accessor_bundle;

// Main specialization
template <
    typename Accessor,
    typename ...Accessors
>
class accessor_bundle<Accessor, Accessors...> {
    typedef Accessor accessor;
    accessor _accessor;

    typedef accessor_bundle<Accessors...> next;
    next _next;

public:
    /**
     * The C++ type which may be accessed using the accessor bundle
     */
    typedef typename std::conditional<
        util::count<Accessors...>::value == 0,
        typename accessor::object_type,
        typename next::object_type
    >::type object_type;
    static_assert(
        std::is_same<typename accessor::object_type, object_type>::value,
        "All accessors in a bundle must have the same object type"
    );

    accessor_bundle(accessor current, Accessors... accessors) :
            _accessor(std::forward<accessor>(current)),
            _next(std::forward<Accessors>(accessors)...) {};
    accessor_bundle(accessor_bundle const&) = default;
    accessor_bundle(accessor_bundle&&) = default;
    accessor_bundle() = delete;

    /**
     * Get the value of a specific attribute from an object
     *
     * \returns the value of the attribute
     */
    template <typename Attribute>
    typename std::enable_if<
        !std::is_same<Attribute, typename accessor::attr>::value,
        typename Attribute::type
    >::type
    get(
        object_type const& obj ///< object from which to get the value
    ) const {
        return _next.template get<Attribute>(obj);
    }

    template <typename Attribute>
    typename std::enable_if<
        std::is_same<Attribute, typename accessor::attr>::value,
        typename Attribute::type
    >::type
    get(
        object_type const& obj ///< object from which to get the value
    ) const {
        return _accessor.get(obj);
    }

    /**
     * Set the value of a specific attribute on an object
     */
    template <typename Attribute>
    typename std::enable_if<
        !std::is_same<Attribute, typename accessor::attr>::value
    >::type
    set(
        object_type& obj, ///< object on which to set the attribute
        typename Attribute::type&& value ///< value to set
    ) const {
        _next.template set<Attribute>(obj, std::forward<typename Attribute::type>(value));
    }

    template <typename Attribute>
    typename std::enable_if<
        std::is_same<Attribute, typename accessor::attr>::value
    >::type
    set(
        object_type& obj, ///< object on which to set the attribute
        typename Attribute::type&& value ///< value to set
    ) const {
        _accessor.set(obj, std::forward<typename Attribute::type>(value));
    }
};

// Recursion terminator
template <>
class accessor_bundle<> {
public:
    typedef void object_type;

    // accept whatever comes in and error out
    template <typename Attribute, typename ObjectType>
    typename Attribute::type
    get(
        ObjectType const& obj
    ) const {
        static_assert(
            true,
            "The attribute can not be accessed via this bundle."
        );
    }

    // accept whatever comes in and error out
    template <typename ObjectType, typename Value>
    void
    get(
        ObjectType const& obj,
        Value&& value
    ) const {
        static_assert(
            true,
            "The attribute can not be accessed via this bundle."
        );
    }
};

/**
 * Construct an accessor bundle from a bunch of accessors
 *
 * \returns an accessor bundle holding all the accessors supplied
 */
template <
    typename ...Accessors
>
constexpr
const
accessor_bundle<Accessors...>
bundle(
    Accessors... accessors ///< accessors to bundle
) {
    return accessor_bundle<Accessors...>(std::forward<Accessors>(accessors)...);
}

}

#endif
<commit_msg>Fix cmoh::bundle() factory<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Julian Ganz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifndef CMOH_ACCESSOR_BUNDLE_HPP__
#define CMOH_ACCESSOR_BUNDLE_HPP__

// std includes
#include <type_traits>
#include <utility>

// local includes
#include <cmoh/utils.hpp>

namespace cmoh {

/**
 * Accessor bundle
 *
 * Instantiations of this template bundle accessors and make them conveniently
 * accessible as a group, posing as an abstraction layer.
 *
 * TODO: further explanation
 *
 * Users are discouraged from constructing accessor bundles directly. Use
 * `bundle()` instread as a factory.
 */
template <
    typename ...Accessors
>
class accessor_bundle;

// Main specialization
template <
    typename Accessor,
    typename ...Accessors
>
class accessor_bundle<Accessor, Accessors...> {
    typedef Accessor accessor;
    accessor _accessor;

    typedef accessor_bundle<Accessors...> next;
    next _next;

public:
    /**
     * The C++ type which may be accessed using the accessor bundle
     */
    typedef typename std::conditional<
        util::count<Accessors...>::value == 0,
        typename accessor::object_type,
        typename next::object_type
    >::type object_type;
    static_assert(
        std::is_same<typename accessor::object_type, object_type>::value,
        "All accessors in a bundle must have the same object type"
    );

    accessor_bundle(accessor current, Accessors... accessors) :
            _accessor(std::forward<accessor>(current)),
            _next(std::forward<Accessors>(accessors)...) {};
    accessor_bundle(accessor_bundle const&) = default;
    accessor_bundle(accessor_bundle&&) = default;
    accessor_bundle() = delete;

    /**
     * Get the value of a specific attribute from an object
     *
     * \returns the value of the attribute
     */
    template <typename Attribute>
    typename std::enable_if<
        !std::is_same<Attribute, typename accessor::attr>::value,
        typename Attribute::type
    >::type
    get(
        object_type const& obj ///< object from which to get the value
    ) const {
        return _next.template get<Attribute>(obj);
    }

    template <typename Attribute>
    typename std::enable_if<
        std::is_same<Attribute, typename accessor::attr>::value,
        typename Attribute::type
    >::type
    get(
        object_type const& obj ///< object from which to get the value
    ) const {
        return _accessor.get(obj);
    }

    /**
     * Set the value of a specific attribute on an object
     */
    template <typename Attribute>
    typename std::enable_if<
        !std::is_same<Attribute, typename accessor::attr>::value
    >::type
    set(
        object_type& obj, ///< object on which to set the attribute
        typename Attribute::type&& value ///< value to set
    ) const {
        _next.template set<Attribute>(obj, std::forward<typename Attribute::type>(value));
    }

    template <typename Attribute>
    typename std::enable_if<
        std::is_same<Attribute, typename accessor::attr>::value
    >::type
    set(
        object_type& obj, ///< object on which to set the attribute
        typename Attribute::type&& value ///< value to set
    ) const {
        _accessor.set(obj, std::forward<typename Attribute::type>(value));
    }
};

// Recursion terminator
template <>
class accessor_bundle<> {
public:
    typedef void object_type;

    // accept whatever comes in and error out
    template <typename Attribute, typename ObjectType>
    typename Attribute::type
    get(
        ObjectType const& obj
    ) const {
        static_assert(
            true,
            "The attribute can not be accessed via this bundle."
        );
    }

    // accept whatever comes in and error out
    template <typename ObjectType, typename Value>
    void
    get(
        ObjectType const& obj,
        Value&& value
    ) const {
        static_assert(
            true,
            "The attribute can not be accessed via this bundle."
        );
    }
};

/**
 * Construct an accessor bundle from a bunch of accessors
 *
 * \returns an accessor bundle holding all the accessors supplied
 */
template <
    typename ...Accessors
>
constexpr
const
accessor_bundle<Accessors...>
bundle(
    Accessors&&... accessors ///< accessors to bundle
) {
    return accessor_bundle<Accessors...>(std::forward<Accessors>(accessors)...);
}

}

#endif
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include "arduino.h"
//#include <core_msgs/Odom.h>
#include <buzzmobile/CarPose.h>
//#include <core_msgs/MotionCommand.h>
#include <std_msgs/Bool.h>

using namespace std;

const double ticksPerRev = 3600;
const double wheelCirc = 2.198;

ros::Publisher encoder_pub;
ros::Subscriber command_sub;
//ros::Subscriber horn_sub;

Arduino arduino;

//int odom_sequence = 0;

ros::Time last_command_time;

ros::Duration keep_alive_frequency(1.0);

//void odometry_callback(int, float);

//void command_callback(core_msgs::MotionCommand::ConstPtr);
void command_callback(buzzmobile::CarPose::ConstPtr);

//void horn_callback(std_msgs::Bool::ConstPtr);

void keep_alive_callback(const ros::TimerEvent&);

int main(int argc, char **argv) {

  ros::init(argc, argv, "car_interface");

  //arduino.open("/dev/arduino_motor_controller", 9600);
  arduino.open("/dev/ttyACM0", 9600);
  //arduino.setOdometryCallback(odometry_callback);

  ros::NodeHandle node_handle;

  last_command_time = ros::Time::now();

  //encoder_pub = node_handle.advertise<core_msgs::Odom>("encoder_odom", 1000);

  command_sub = node_handle.subscribe("car_pose", 1, command_callback);

  //horn_sub = node_handle.subscribe("car_horn", 1, horn_callback);

  ros::Timer keepAliveTimer = node_handle.createTimer(keep_alive_frequency, keep_alive_callback);
  ros::spin();

  return 0;
}

void keep_alive_callback(const ros::TimerEvent&) {
  ROS_INFO("Keep alive callback called");
  // 1 sec command frequency required to maintain velocity
  if((ros::Time::now() - last_command_time) > keep_alive_frequency) {
    arduino.setSpeed(0);
  }
}
/**
void odometry_callback(int tickCount, float steeringAngle) {
  core_msgs::Odom msg;
  msg.distance_travelled = (tickCount * wheelCirc) / ticksPerRev;
  msg.steering_angle = steeringAngle;
  msg.header.seq = odom_sequence++;
  msg.header.stamp = ros::Time::now();
  encoder_pub.publish(msg);
}*/

//void command_callback(core_msgs::MotionCommand::ConstPtr cmd) {
void command_callback(buzzmobile::CarPose::ConstPtr cmd) {
  ROS_INFO("Command received, speed: %f, angle: %f", cmd->velocity, cmd->angle);
  //arduino.setSpeed(cmd->speed);
  arduino.setSpeed(cmd->velocity);
  arduino.setSteering(cmd->angle);
  arduino.setHorn(cmd->horn);
  last_command_time = cmd->header.stamp;
}

//void horn_callback(std_msgs::Bool::ConstPtr msg) {
  //ROS_INFO("Turning %s horn.", (msg->data ? "on" : "off"));
  //arduino.setHorn(msg->data);
//}
<commit_msg>Delete comments<commit_after>#include <ros/ros.h>
#include "arduino.h"
//#include <core_msgs/Odom.h>
#include <buzzmobile/CarPose.h>
//#include <core_msgs/MotionCommand.h>
#include <std_msgs/Bool.h>

using namespace std;

const double ticksPerRev = 3600;
const double wheelCirc = 2.198;

ros::Publisher encoder_pub;
ros::Subscriber command_sub;

Arduino arduino;

//int odom_sequence = 0;

ros::Time last_command_time;

ros::Duration keep_alive_frequency(1.0);

//void odometry_callback(int, float);

//void command_callback(core_msgs::MotionCommand::ConstPtr);
void command_callback(buzzmobile::CarPose::ConstPtr);

void keep_alive_callback(const ros::TimerEvent&);

int main(int argc, char **argv) {

  ros::init(argc, argv, "car_interface");

  //arduino.open("/dev/arduino_motor_controller", 9600);
  arduino.open("/dev/ttyACM0", 9600);
  //arduino.setOdometryCallback(odometry_callback);

  ros::NodeHandle node_handle;

  last_command_time = ros::Time::now();

  //encoder_pub = node_handle.advertise<core_msgs::Odom>("encoder_odom", 1000);

  command_sub = node_handle.subscribe("car_pose", 1, command_callback);

  ros::Timer keepAliveTimer = node_handle.createTimer(keep_alive_frequency, keep_alive_callback);
  ros::spin();

  return 0;
}

void keep_alive_callback(const ros::TimerEvent&) {
  ROS_INFO("Keep alive callback called");
  // 1 sec command frequency required to maintain velocity
  if((ros::Time::now() - last_command_time) > keep_alive_frequency) {
    arduino.setSpeed(0);
  }
}
/**
void odometry_callback(int tickCount, float steeringAngle) {
  core_msgs::Odom msg;
  msg.distance_travelled = (tickCount * wheelCirc) / ticksPerRev;
  msg.steering_angle = steeringAngle;
  msg.header.seq = odom_sequence++;
  msg.header.stamp = ros::Time::now();
  encoder_pub.publish(msg);
}*/

//void command_callback(core_msgs::MotionCommand::ConstPtr cmd) {
void command_callback(buzzmobile::CarPose::ConstPtr cmd) {
  ROS_INFO("Command received, speed: %f, angle: %f", cmd->velocity, cmd->angle);
  //arduino.setSpeed(cmd->speed);
  arduino.setSpeed(cmd->velocity);
  arduino.setSteering(cmd->angle);
  arduino.setHorn(cmd->horn);
  last_command_time = cmd->header.stamp;
}

//void horn_callback(std_msgs::Bool::ConstPtr msg) {
  //ROS_INFO("Turning %s horn.", (msg->data ? "on" : "off"));
  //arduino.setHorn(msg->data);
//}
<|endoftext|>


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

#include "gm.h"
#include "SkCanvas.h"
#include "SkPath.h"
#include "SkGradientShader.h"
#include "SkTypeface.h"

static SkShader* make_heatGradient(const SkPoint pts[2]) {
#if 0 // UNUSED
    const SkColor colors[] = {
        SK_ColorBLACK, SK_ColorBLUE, SK_ColorCYAN, SK_ColorGREEN,
        SK_ColorYELLOW, SK_ColorRED, SK_ColorWHITE
    };
#endif
    const SkColor bw[] = { SK_ColorBLACK, SK_ColorWHITE };

    return SkGradientShader::CreateLinear(pts, bw, NULL,
                                          SK_ARRAY_COUNT(bw),
                                          SkShader::kClamp_TileMode);
}

static bool setFont(SkPaint* paint, const char name[]) {
    SkTypeface* tf = sk_tool_utils::create_portable_typeface(name, SkTypeface::kNormal);
    if (tf) {
        paint->setTypeface(tf)->unref();
        return true;
    }
    return false;
}

#ifdef SK_BUILD_FOR_MAC
#import <ApplicationServices/ApplicationServices.h>
#define BITMAP_INFO_RGB     (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)

static CGContextRef makeCG(const SkImageInfo& info, const void* addr,
                           size_t rowBytes) {
    if (kN32_SkColorType != info.colorType() || NULL == addr) {
        return NULL;
    }
    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
    CGContextRef cg = CGBitmapContextCreate((void*)addr, info.width(), info.height(),
                                            8, rowBytes, space, BITMAP_INFO_RGB);
    CFRelease(space);

    CGContextSetAllowsFontSubpixelQuantization(cg, false);
    CGContextSetShouldSubpixelQuantizeFonts(cg, false);

    return cg;
}

extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);

static CGFontRef typefaceToCGFont(const SkTypeface* face) {
    if (NULL == face) {
        return 0;
    }

    CTFontRef ct = SkTypeface_GetCTFontRef(face);
    return CTFontCopyGraphicsFont(ct, NULL);
}

static void cgSetPaintForText(CGContextRef cg, const SkPaint& paint) {
    SkColor c = paint.getColor();
    CGFloat rgba[] = {
        SkColorGetB(c) / 255.0f,
        SkColorGetG(c) / 255.0f,
        SkColorGetR(c) / 255.0f,
        SkColorGetA(c) / 255.0f,
    };
    CGContextSetRGBFillColor(cg, rgba[0], rgba[1], rgba[2], rgba[3]);

    CGContextSetTextDrawingMode(cg, kCGTextFill);
    CGContextSetFont(cg, typefaceToCGFont(paint.getTypeface()));
    CGContextSetFontSize(cg, SkScalarToFloat(paint.getTextSize()));

    CGContextSetAllowsFontSubpixelPositioning(cg, paint.isSubpixelText());
    CGContextSetShouldSubpixelPositionFonts(cg, paint.isSubpixelText());

    CGContextSetShouldAntialias(cg, paint.isAntiAlias());
    CGContextSetShouldSmoothFonts(cg, paint.isLCDRenderText());
}

static void cgDrawText(CGContextRef cg, const void* text, size_t len,
                       float x, float y, const SkPaint& paint) {
    if (cg) {
        cgSetPaintForText(cg, paint);

        uint16_t glyphs[200];
        int count = paint.textToGlyphs(text, len, glyphs);

        CGContextShowGlyphsAtPoint(cg, x, y, glyphs, count);
    }
}
#endif

/**
   Test a set of clipping problems discovered while writing blitAntiRect,
   and test all the code paths through the clipping blitters.
   Each region should show as a blue center surrounded by a 2px green
   border, with no red.
*/

#define HEIGHT 480

class GammaTextGM : public skiagm::GM {
public:
    GammaTextGM() {

    }

protected:
    virtual SkString onShortName() {
        return SkString("gammatext");
    }

    virtual SkISize onISize() {
        return SkISize::Make(1024, HEIGHT);
    }

    static void drawGrad(SkCanvas* canvas) {
        SkPoint pts[] = { { 0, 0 }, { 0, SkIntToScalar(HEIGHT) } };
#if 0
        const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
        SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
#else
        SkShader* s = make_heatGradient(pts);
#endif

        canvas->clear(SK_ColorRED);
        SkPaint paint;
        paint.setShader(s)->unref();
        SkRect r = { 0, 0, SkIntToScalar(1024), SkIntToScalar(HEIGHT) };
        canvas->drawRect(r, paint);
    }

    virtual void onDraw(SkCanvas* canvas) {
#ifdef SK_BUILD_FOR_MAC
        CGContextRef cg = 0;
        {
            SkImageInfo info;
            size_t rowBytes;
            const void* addr = canvas->peekPixels(&info, &rowBytes);
            if (addr) {
                cg = makeCG(info, addr, rowBytes);
            }
        }
#endif

        drawGrad(canvas);

        const SkColor fg[] = {
            0xFFFFFFFF,
            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
            0xFF000000,
        };

        const char* text = "Hamburgefons";
        size_t len = strlen(text);

        SkPaint paint;
        setFont(&paint, "Times");
        paint.setTextSize(SkIntToScalar(16));
        paint.setAntiAlias(true);
        paint.setLCDRenderText(true);

        SkScalar x = SkIntToScalar(10);
        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
            paint.setColor(fg[i]);

            SkScalar y = SkIntToScalar(40);
            SkScalar stopy = SkIntToScalar(HEIGHT);
            while (y < stopy) {
                if (true) {
                    canvas->drawText(text, len, x, y, paint);
                }
#ifdef SK_BUILD_FOR_MAC
                else {
                    cgDrawText(cg, text, len, SkScalarToFloat(x),
                               static_cast<float>(HEIGHT) - SkScalarToFloat(y),
                               paint);
                }
#endif
                y += paint.getTextSize() * 2;
            }
            x += SkIntToScalar(1024) / SK_ARRAY_COUNT(fg);
        }
#ifdef SK_BUILD_FOR_MAC
        CGContextRelease(cg);
#endif
    }

private:
    typedef skiagm::GM INHERITED;
};

DEF_GM( return new GammaTextGM; )

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

static SkShader* make_gradient(SkColor c) {
    const SkPoint pts[] = { { 0, 0 }, { 240, 0 } };
    SkColor colors[2];
    colors[0] = c;
    colors[1] = SkColorSetA(c, 0);
    return SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
}

static void set_face(SkPaint* paint) {
    SkTypeface* face = SkTypeface::CreateFromName("serif", SkTypeface::kItalic);
    SkSafeUnref(paint->setTypeface(face));
}

static void draw_pair(SkCanvas* canvas, SkPaint* paint, SkShader* shader) {
    const char text[] = "Now is the time for all good";
    const size_t len = strlen(text);

    paint->setShader(NULL);
    canvas->drawText(text, len, 10, 20, *paint);
    paint->setShader(SkShader::CreateColorShader(paint->getColor()))->unref();
    canvas->drawText(text, len, 10, 40, *paint);
    paint->setShader(shader);
    canvas->drawText(text, len, 10, 60, *paint);
}

class GammaShaderTextGM : public skiagm::GM {
    SkShader* fShaders[3];
    SkColor fColors[3];

public:
    GammaShaderTextGM() {
        const SkColor colors[] = { SK_ColorBLACK, SK_ColorRED, SK_ColorBLUE };
        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            fShaders[i] = NULL;
            fColors[i] = colors[i];
        }
    }

    virtual ~GammaShaderTextGM() {
        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            SkSafeUnref(fShaders[i]);
        }
    }

protected:
    virtual SkString onShortName() {
        return SkString("gammagradienttext");
    }

    virtual SkISize onISize() {
        return SkISize::Make(300, 300);
    }

    virtual void onOnceBeforeDraw() {
        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            fShaders[i] = make_gradient(fColors[i]);
        }
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setLCDRenderText(true);
        paint.setTextSize(18);
        set_face(&paint);

        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            paint.setColor(fColors[i]);
            draw_pair(canvas, &paint, fShaders[i]);
            canvas->translate(0, 80);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};

DEF_GM( return new GammaShaderTextGM; )

<commit_msg>clean up dead code<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkCanvas.h"
#include "SkPath.h"
#include "SkGradientShader.h"
#include "SkTypeface.h"

static SkShader* make_heatGradient(const SkPoint pts[2]) {
    const SkColor bw[] = { SK_ColorBLACK, SK_ColorWHITE };

    return SkGradientShader::CreateLinear(pts, bw, NULL,
                                          SK_ARRAY_COUNT(bw),
                                          SkShader::kClamp_TileMode);
}

static bool setFont(SkPaint* paint, const char name[]) {
    SkTypeface* tf = sk_tool_utils::create_portable_typeface(name, SkTypeface::kNormal);
    if (tf) {
        paint->setTypeface(tf)->unref();
        return true;
    }
    return false;
}

/**
   Test a set of clipping problems discovered while writing blitAntiRect,
   and test all the code paths through the clipping blitters.
   Each region should show as a blue center surrounded by a 2px green
   border, with no red.
*/

#define HEIGHT 480

class GammaTextGM : public skiagm::GM {
protected:
    SkString onShortName() SK_OVERRIDE {
        return SkString("gammatext");
    }

    SkISize onISize() SK_OVERRIDE {
        return SkISize::Make(1024, HEIGHT);
    }

    static void drawGrad(SkCanvas* canvas) {
        SkPoint pts[] = { { 0, 0 }, { 0, SkIntToScalar(HEIGHT) } };
        SkShader* s = make_heatGradient(pts);

        canvas->clear(SK_ColorRED);
        SkPaint paint;
        paint.setShader(s)->unref();
        SkRect r = { 0, 0, SkIntToScalar(1024), SkIntToScalar(HEIGHT) };
        canvas->drawRect(r, paint);
    }

    void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        drawGrad(canvas);

        const SkColor fg[] = {
            0xFFFFFFFF,
            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
            0xFF000000,
        };

        const char* text = "Hamburgefons";
        size_t len = strlen(text);

        SkPaint paint;
        setFont(&paint, "Times");
        paint.setTextSize(SkIntToScalar(16));
        paint.setAntiAlias(true);
        paint.setLCDRenderText(true);

        SkScalar x = SkIntToScalar(10);
        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
            paint.setColor(fg[i]);

            SkScalar y = SkIntToScalar(40);
            SkScalar stopy = SkIntToScalar(HEIGHT);
            while (y < stopy) {
                canvas->drawText(text, len, x, y, paint);
                y += paint.getTextSize() * 2;
            }
            x += SkIntToScalar(1024) / SK_ARRAY_COUNT(fg);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};

DEF_GM( return new GammaTextGM; )

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

static SkShader* make_gradient(SkColor c) {
    const SkPoint pts[] = { { 0, 0 }, { 240, 0 } };
    SkColor colors[2];
    colors[0] = c;
    colors[1] = SkColorSetA(c, 0);
    return SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
}

static void set_face(SkPaint* paint) {
    SkTypeface* face = SkTypeface::CreateFromName("serif", SkTypeface::kItalic);
    SkSafeUnref(paint->setTypeface(face));
}

static void draw_pair(SkCanvas* canvas, SkPaint* paint, SkShader* shader) {
    const char text[] = "Now is the time for all good";
    const size_t len = strlen(text);

    paint->setShader(NULL);
    canvas->drawText(text, len, 10, 20, *paint);
    paint->setShader(SkShader::CreateColorShader(paint->getColor()))->unref();
    canvas->drawText(text, len, 10, 40, *paint);
    paint->setShader(shader);
    canvas->drawText(text, len, 10, 60, *paint);
}

class GammaShaderTextGM : public skiagm::GM {
    SkShader* fShaders[3];
    SkColor fColors[3];

public:
    GammaShaderTextGM() {
        const SkColor colors[] = { SK_ColorBLACK, SK_ColorRED, SK_ColorBLUE };
        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            fShaders[i] = NULL;
            fColors[i] = colors[i];
        }
    }

    virtual ~GammaShaderTextGM() SK_OVERRIDE {
        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            SkSafeUnref(fShaders[i]);
        }
    }

protected:
    SkString onShortName() SK_OVERRIDE {
        return SkString("gammagradienttext");
    }

    SkISize onISize() SK_OVERRIDE {
        return SkISize::Make(300, 300);
    }

    void onOnceBeforeDraw() SK_OVERRIDE {
        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            fShaders[i] = make_gradient(fColors[i]);
        }
    }

    void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setLCDRenderText(true);
        paint.setTextSize(18);
        set_face(&paint);

        for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) {
            paint.setColor(fColors[i]);
            draw_pair(canvas, &paint, fShaders[i]);
            canvas->translate(0, 80);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};

DEF_GM( return new GammaShaderTextGM; )

<|endoftext|>


<commit_before>// @(#)root/net:$Name:  $:$Id: TGrid.cxx,v 1.9 2005/05/20 09:59:35 rdm Exp $
// Author: Fons Rademakers   3/1/2002

/*************************************************************************
 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGrid                                                                //
//                                                                      //
// Abstract base class defining interface to common GRID services.      //
//                                                                      //
// To open a connection to a GRID use the static method Connect().      //
// The argument of Connect() is of the form:                            //
//    <grid>[://<host>][:<port>], e.g.                                  //
// alien, alien://alice.cern.ch, globus://glsvr1.cern.ch, ...           //
// Depending on the <grid> specified an appropriate plugin library      //
// will be loaded which will provide the real interface.                //
//                                                                      //
// Related classes are TGridResult.                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGrid.h"
#include "TUrl.h"
#include "TROOT.h"
#include "TPluginManager.h"
#include "TFile.h"
#include "TList.h"
#include "TError.h"
#include "TUUID.h"
#include "TSystem.h"
#include "TH1.h"
#include "TChain.h"
#include "TKey.h"

TGrid *gGrid = 0;

ClassImp(TGrid)

//______________________________________________________________________________
TGrid::TGrid() : fPort(-1), fMergerOutputFile(0)
{
   // Create grid interface object.

   fMergerFileList = new TList;
   fMergerFileList->SetOwner(kTRUE);
}

//______________________________________________________________________________
TGrid *TGrid::Connect(const char *grid, const char *uid, const char *pw,
                      const char *options)
{
   // The grid should be of the form:  <grid>://<host>[:<port>],
   // e.g.:  alien://alice.cern.ch, globus://glsrv1.cern.ch, ...
   // The uid is the username and pw the password that should be used for
   // the connection. Depending on the <grid> the shared library (plugin)
   // for the selected system will be loaded. When the connection could not
   // be opened 0 is returned. For AliEn the supported options are:
   // -domain=<domain name>
   // -debug=<debug level from 1 to 10>
   // Example: "-domain=cern.ch -debug=5"

   TPluginHandler *h;
   TGrid *g = 0;

   if (!grid) {
      ::Error("TGrid::Connect", "no grid specified");
      return 0;
   }
   if (!uid)
      uid = "";
   if (!pw)
      pw = "";
   if (!options)
      options = "";

   if ((h = gROOT->GetPluginManager()->FindHandler("TGrid", grid))) {
      if (h->LoadPlugin() == -1)
         return 0;
      g = (TGrid *) h->ExecPlugin(4, grid, uid, pw, options);
   }

   return g;
}

//______________________________________________________________________________
TGrid::~TGrid()
{
   // Cleanup.

  if (fMergerFileList)
    delete fMergerFileList;

  if (fMergerOutputFile)
    delete fMergerOutputFile;
}

//______________________________________________________________________________
void TGrid::PrintProgress(Long64_t bytesread, Long64_t size)
{
   // Print file copy progress.

   fprintf(stderr, "[TGrid::Cp] Total %.02f MB\t|", (Double_t)size/1048576);
   for (int l = 0; l < 20; l++) {
      if (l < 20*bytesread/size)
         fprintf(stderr, "=");
      if (l == 20*bytesread/size)
         fprintf(stderr, ">");
      if (l > 20*bytesread/size)
         fprintf(stderr, ".");
   }

   fWatch.Stop();
   Double_t lCopy_time = fWatch.RealTime();
   fprintf(stderr, "| %.02f %% [%.01f MB/s]\r",
          100.0*bytesread/size, bytesread/lCopy_time/1048576.);
   fWatch.Continue();
}

//______________________________________________________________________________
Bool_t TGrid::Cp(const char *src, const char *dst, Bool_t progressbar,
                 UInt_t buffersize)
{
   // Allows to copy file from src to dst URL.

   Bool_t success = kFALSE;

   TUrl sURL(src, kTRUE);
   TUrl dURL(dst, kTRUE);

   char *copybuffer = 0;

   TFile *sfile = 0;
   TFile *dfile = 0;

   sfile = TFile::Open(src, "-READ");

   if (!sfile) {
      Error("Cp", "cannot open source file %s", src);
      goto copyout;
   }

   dfile = TFile::Open(dst, "-RECREATE");

   if (!dfile) {
      Error("Cp", "cannot open destination file %s", dst);
      goto copyout;
   }

   sfile->Seek(0);
   dfile->Seek(0);

   copybuffer = new char[buffersize];
   if (!copybuffer) {
      Error("Cp", "cannot allocate the copy buffer");
      goto copyout;
   }

   Bool_t   readop;
   Bool_t   writeop;
   Long64_t read;
   Long64_t written;
   Long64_t totalread;
   Long64_t filesize;
   Long64_t b00;
   filesize  = sfile->GetSize();
   totalread = 0;
   fWatch.Start();

   b00 = (Long64_t)sfile->GetBytesRead();

   do {
      if (progressbar) PrintProgress(totalread, filesize);

      Long64_t b1 = (Long64_t)sfile->GetBytesRead() - b00;

      Long64_t readsize;
      if (filesize - b1 > (Long64_t)buffersize) {
         readsize = buffersize;
      } else {
         readsize = filesize - b1;
      }

      Long64_t b0 = (Long64_t)sfile->GetBytesRead();
      readop = sfile->ReadBuffer(copybuffer, readsize);
      read   = (Long64_t)sfile->GetBytesRead() - b0;
      if (read < 0) {
         Error("Cp", "cannot read from source file %s", src);
         goto copyout;
      }

      Long64_t w0 = (Long64_t)dfile->GetBytesWritten();
      writeop = dfile->WriteBuffer(copybuffer, read);
      written = (Long64_t)dfile->GetBytesWritten() - w0;
      if (written != read) {
         Error("Cp", "cannot write %d bytes to destination file %s", read, dst);
         goto copyout;
      }
      totalread += read;
   } while (read == (Long64_t)buffersize);

   if (progressbar) {
      PrintProgress(totalread, filesize);
      fprintf(stderr, "\n");
   }

   success = kTRUE;

copyout:
   if (sfile) sfile->Close();
   if (dfile) dfile->Close();

   if (sfile) delete sfile;
   if (dfile) delete dfile;
   if (copybuffer) delete copybuffer;

   fWatch.Stop();
   fWatch.Reset();

   return success;
}

//______________________________________________________________________________
void TGrid::MergerReset()
{
   // Reset merger file list.

   fMergerFileList->Clear();
}

//______________________________________________________________________________
Bool_t TGrid::MergerAddFile(const char *url)
{
   // Add file to file merger.

   TUUID uuid;
   TString localcopy = "file:/tmp/";
   localcopy += "ROOTMERGE-";
   localcopy += uuid.AsString();
   localcopy += ".root";

   if (!Cp(url, localcopy)) {
      Error("MergerAddFile", "cannot get a local copy of file %s", url);
      return kFALSE;
   }

   TFile *newfile = TFile::Open(localcopy, "READ");
   if (!newfile) {
      Error("MergerAddFile", "cannot open local copy %s of URL %s",
            localcopy.Data(), url);
      return kFALSE;
   } else {
      fMergerFileList->Add(newfile);
      return  kTRUE;
   }
}

//______________________________________________________________________________
Bool_t TGrid::MergerOutputFile(const char *outputfile)
{
   // Open merger output file.

   if (fMergerOutputFile)
      delete fMergerOutputFile;

   fMergerOutputFilename = outputfile;

   TUUID uuid;
   TString localcopy = "file:/tmp/";
   localcopy += "ROOTMERGED-";
   localcopy += uuid.AsString();
   localcopy += ".root";

   fMergerOutputFile = TFile::Open(localcopy, "RECREATE");
   fMergerOutputFilename1 = localcopy;

   if (!fMergerOutputFile) {
      Error("MergerOutputFile", "cannot open the MERGER outputfile %s", localcopy.Data());
      return kFALSE;
   }
   return kTRUE;
}

//______________________________________________________________________________
void TGrid::MergerPrintFiles(Option_t *options)
{
   // Print list of files being merged.

   fMergerFileList->Print(options);
}

//______________________________________________________________________________
Bool_t TGrid::MergerMerge()
{
   // Merge the files.

   if (!fMergerOutputFile) {
      Info("MergerMerge", "will merge the results to the file "
           "GridMergerMerged.root in your working directory, "
           "since you didn't specify a merge filename");
      if (!MergerOutputFile("GridMergerMerged.root")) {
         return kFALSE;
      }
   }

   Bool_t result = MergerMergeRecursive(fMergerOutputFile, fMergerFileList);
   if (!result) {
      Error("MergerMerge", "error during merge of your ROOT files");
   } else {
      fMergerOutputFile->Write();
      // copy the result file to the final destination
      Cp(fMergerOutputFilename1, fMergerOutputFilename);
   }

   // remove the temporary result file
   TString path(fMergerOutputFile->GetPath());
   path = path(0, path.Index(':',0));
   gSystem->Unlink(path);
   fMergerOutputFile = 0;

   TIter next(fMergerFileList);
   TFile *file;
   while ((file = (TFile*) next())) {
      // close the files
      file->Close();
      // remove the temporary files
      TString path(file->GetPath());
      path = path(0, path.Index(':',0));
      gSystem->Unlink(path);
   }
   return result;
}

//______________________________________________________________________________
Bool_t TGrid::MergerMergeRecursive(TDirectory *target, TList *sourcelist)
{
   // Recursively merge objects in the ROOT files.

   TString path(strstr(target->GetPath(), ":"));
   path.Remove(0, 2);

   TFile *first_source = (TFile*)sourcelist->First();
   first_source->cd(path);
   TDirectory *current_sourcedir = gDirectory;

   TChain *globChain = 0;
   TIter nextkey(current_sourcedir->GetListOfKeys());
   TKey *key;
   Bool_t success = kTRUE;

   // gain time, do not add the objects in the list in memory
   TH1::AddDirectory(kFALSE);

   while ((key = (TKey*) nextkey())) {
      first_source->cd(path);
      TObject *obj = key->ReadObj();

      if (obj->IsA()->InheritsFrom("TH1")) {
         Info("MergerMergeRecursive", "merging histogram %s", obj->GetName());
         TH1 *h1 = (TH1*)obj;

         TFile *nextsource = (TFile*)sourcelist->After(first_source);
         while (nextsource) {

            nextsource->cd(path);
            TH1 *h2 = (TH1*)gDirectory->Get(h1->GetName());
            if (h2) {
               h1->Add(h2);
               delete h2;
            }

            nextsource = (TFile*)sourcelist->After(nextsource);
         }
      } else if (obj->IsA()->InheritsFrom("TTree")) {
         Info("MergerMergeRecursive", "merging tree %s", obj->GetName());
         const char *obj_name= obj->GetName();

         globChain = new TChain(obj_name);
         globChain->Add(first_source->GetName());
         TFile *nextsource = (TFile*)sourcelist->After(first_source);
         while (nextsource) {
            globChain->Add(nextsource->GetName());
            nextsource = (TFile*)sourcelist->After(nextsource);
         }

      } else if (obj->IsA()->InheritsFrom("TDirectory")) {
         target->cd();
         TDirectory *newdir = target->mkdir(obj->GetName(), obj->GetTitle());
         if (!MergerMergeRecursive(newdir, sourcelist)) {
            Error("MergerMergeRecursive", "error during merge of directory %s",
                  newdir->GetPath());
            success = kFALSE;
         }
      } else {
         Error("MergerMergeRecursive", "unknown object type, name: %s title: %s",
               obj->GetName(), obj->GetTitle());
         success = kFALSE;
      }

      if (obj) {
         target->cd();

         if (obj->IsA()->InheritsFrom("TTree")) {
            globChain->Merge(target->GetFile() ,0, "keep");
            delete globChain;
         } else
            obj->Write(key->GetName());
      }

   }  // nextkey

   target->Write();

   TH1::AddDirectory(kTRUE);

   return success;
}
<commit_msg>disable Grid ROOT file merge feature since it would make Core depend on Hist. Looking for better solution.<commit_after>// @(#)root/net:$Name:  $:$Id: TGrid.cxx,v 1.10 2005/05/20 10:33:00 rdm Exp $
// Author: Fons Rademakers   3/1/2002

/*************************************************************************
 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGrid                                                                //
//                                                                      //
// Abstract base class defining interface to common GRID services.      //
//                                                                      //
// To open a connection to a GRID use the static method Connect().      //
// The argument of Connect() is of the form:                            //
//    <grid>[://<host>][:<port>], e.g.                                  //
// alien, alien://alice.cern.ch, globus://glsvr1.cern.ch, ...           //
// Depending on the <grid> specified an appropriate plugin library      //
// will be loaded which will provide the real interface.                //
//                                                                      //
// Related classes are TGridResult.                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGrid.h"
#include "TUrl.h"
#include "TROOT.h"
#include "TPluginManager.h"
#include "TFile.h"
#include "TList.h"
#include "TError.h"
#include "TUUID.h"
#include "TSystem.h"
//#include "TH1.h"
#include "TChain.h"
#include "TKey.h"

TGrid *gGrid = 0;

ClassImp(TGrid)

//______________________________________________________________________________
TGrid::TGrid() : fPort(-1), fMergerOutputFile(0)
{
   // Create grid interface object.

   fMergerFileList = new TList;
   fMergerFileList->SetOwner(kTRUE);
}

//______________________________________________________________________________
TGrid *TGrid::Connect(const char *grid, const char *uid, const char *pw,
                      const char *options)
{
   // The grid should be of the form:  <grid>://<host>[:<port>],
   // e.g.:  alien://alice.cern.ch, globus://glsrv1.cern.ch, ...
   // The uid is the username and pw the password that should be used for
   // the connection. Depending on the <grid> the shared library (plugin)
   // for the selected system will be loaded. When the connection could not
   // be opened 0 is returned. For AliEn the supported options are:
   // -domain=<domain name>
   // -debug=<debug level from 1 to 10>
   // Example: "-domain=cern.ch -debug=5"

   TPluginHandler *h;
   TGrid *g = 0;

   if (!grid) {
      ::Error("TGrid::Connect", "no grid specified");
      return 0;
   }
   if (!uid)
      uid = "";
   if (!pw)
      pw = "";
   if (!options)
      options = "";

   if ((h = gROOT->GetPluginManager()->FindHandler("TGrid", grid))) {
      if (h->LoadPlugin() == -1)
         return 0;
      g = (TGrid *) h->ExecPlugin(4, grid, uid, pw, options);
   }

   return g;
}

//______________________________________________________________________________
TGrid::~TGrid()
{
   // Cleanup.

  if (fMergerFileList)
    delete fMergerFileList;

  if (fMergerOutputFile)
    delete fMergerOutputFile;
}

//______________________________________________________________________________
void TGrid::PrintProgress(Long64_t bytesread, Long64_t size)
{
   // Print file copy progress.

   fprintf(stderr, "[TGrid::Cp] Total %.02f MB\t|", (Double_t)size/1048576);
   for (int l = 0; l < 20; l++) {
      if (l < 20*bytesread/size)
         fprintf(stderr, "=");
      if (l == 20*bytesread/size)
         fprintf(stderr, ">");
      if (l > 20*bytesread/size)
         fprintf(stderr, ".");
   }

   fWatch.Stop();
   Double_t lCopy_time = fWatch.RealTime();
   fprintf(stderr, "| %.02f %% [%.01f MB/s]\r",
          100.0*bytesread/size, bytesread/lCopy_time/1048576.);
   fWatch.Continue();
}

//______________________________________________________________________________
Bool_t TGrid::Cp(const char *src, const char *dst, Bool_t progressbar,
                 UInt_t buffersize)
{
   // Allows to copy file from src to dst URL.

   Bool_t success = kFALSE;

   TUrl sURL(src, kTRUE);
   TUrl dURL(dst, kTRUE);

   char *copybuffer = 0;

   TFile *sfile = 0;
   TFile *dfile = 0;

   sfile = TFile::Open(src, "-READ");

   if (!sfile) {
      Error("Cp", "cannot open source file %s", src);
      goto copyout;
   }

   dfile = TFile::Open(dst, "-RECREATE");

   if (!dfile) {
      Error("Cp", "cannot open destination file %s", dst);
      goto copyout;
   }

   sfile->Seek(0);
   dfile->Seek(0);

   copybuffer = new char[buffersize];
   if (!copybuffer) {
      Error("Cp", "cannot allocate the copy buffer");
      goto copyout;
   }

   Bool_t   readop;
   Bool_t   writeop;
   Long64_t read;
   Long64_t written;
   Long64_t totalread;
   Long64_t filesize;
   Long64_t b00;
   filesize  = sfile->GetSize();
   totalread = 0;
   fWatch.Start();

   b00 = (Long64_t)sfile->GetBytesRead();

   do {
      if (progressbar) PrintProgress(totalread, filesize);

      Long64_t b1 = (Long64_t)sfile->GetBytesRead() - b00;

      Long64_t readsize;
      if (filesize - b1 > (Long64_t)buffersize) {
         readsize = buffersize;
      } else {
         readsize = filesize - b1;
      }

      Long64_t b0 = (Long64_t)sfile->GetBytesRead();
      readop = sfile->ReadBuffer(copybuffer, readsize);
      read   = (Long64_t)sfile->GetBytesRead() - b0;
      if (read < 0) {
         Error("Cp", "cannot read from source file %s", src);
         goto copyout;
      }

      Long64_t w0 = (Long64_t)dfile->GetBytesWritten();
      writeop = dfile->WriteBuffer(copybuffer, read);
      written = (Long64_t)dfile->GetBytesWritten() - w0;
      if (written != read) {
         Error("Cp", "cannot write %d bytes to destination file %s", read, dst);
         goto copyout;
      }
      totalread += read;
   } while (read == (Long64_t)buffersize);

   if (progressbar) {
      PrintProgress(totalread, filesize);
      fprintf(stderr, "\n");
   }

   success = kTRUE;

copyout:
   if (sfile) sfile->Close();
   if (dfile) dfile->Close();

   if (sfile) delete sfile;
   if (dfile) delete dfile;
   if (copybuffer) delete copybuffer;

   fWatch.Stop();
   fWatch.Reset();

   return success;
}

//______________________________________________________________________________
void TGrid::MergerReset()
{
   // Reset merger file list.

   fMergerFileList->Clear();
}

//______________________________________________________________________________
Bool_t TGrid::MergerAddFile(const char *url)
{
   // Add file to file merger.

   TUUID uuid;
   TString localcopy = "file:/tmp/";
   localcopy += "ROOTMERGE-";
   localcopy += uuid.AsString();
   localcopy += ".root";

   if (!Cp(url, localcopy)) {
      Error("MergerAddFile", "cannot get a local copy of file %s", url);
      return kFALSE;
   }

   TFile *newfile = TFile::Open(localcopy, "READ");
   if (!newfile) {
      Error("MergerAddFile", "cannot open local copy %s of URL %s",
            localcopy.Data(), url);
      return kFALSE;
   } else {
      fMergerFileList->Add(newfile);
      return  kTRUE;
   }
}

//______________________________________________________________________________
Bool_t TGrid::MergerOutputFile(const char *outputfile)
{
   // Open merger output file.

   if (fMergerOutputFile)
      delete fMergerOutputFile;

   fMergerOutputFilename = outputfile;

   TUUID uuid;
   TString localcopy = "file:/tmp/";
   localcopy += "ROOTMERGED-";
   localcopy += uuid.AsString();
   localcopy += ".root";

   fMergerOutputFile = TFile::Open(localcopy, "RECREATE");
   fMergerOutputFilename1 = localcopy;

   if (!fMergerOutputFile) {
      Error("MergerOutputFile", "cannot open the MERGER outputfile %s", localcopy.Data());
      return kFALSE;
   }
   return kTRUE;
}

//______________________________________________________________________________
void TGrid::MergerPrintFiles(Option_t *options)
{
   // Print list of files being merged.

   fMergerFileList->Print(options);
}

//______________________________________________________________________________
Bool_t TGrid::MergerMerge()
{
   // Merge the files.

   if (!fMergerOutputFile) {
      Info("MergerMerge", "will merge the results to the file "
           "GridMergerMerged.root in your working directory, "
           "since you didn't specify a merge filename");
      if (!MergerOutputFile("GridMergerMerged.root")) {
         return kFALSE;
      }
   }

   Bool_t result = MergerMergeRecursive(fMergerOutputFile, fMergerFileList);
   if (!result) {
      Error("MergerMerge", "error during merge of your ROOT files");
   } else {
      fMergerOutputFile->Write();
      // copy the result file to the final destination
      Cp(fMergerOutputFilename1, fMergerOutputFilename);
   }

   // remove the temporary result file
   TString path(fMergerOutputFile->GetPath());
   path = path(0, path.Index(':',0));
   gSystem->Unlink(path);
   fMergerOutputFile = 0;

   TIter next(fMergerFileList);
   TFile *file;
   while ((file = (TFile*) next())) {
      // close the files
      file->Close();
      // remove the temporary files
      TString path(file->GetPath());
      path = path(0, path.Index(':',0));
      gSystem->Unlink(path);
   }
   return result;
}

//______________________________________________________________________________
Bool_t TGrid::MergerMergeRecursive(TDirectory *target, TList *sourcelist)
{
   // Recursively merge objects in the ROOT files.

#if 1
   // TO BE FIXEd
   if (target || sourcelist) { }
   return kFALSE;
#else
   TString path(strstr(target->GetPath(), ":"));
   path.Remove(0, 2);

   TFile *first_source = (TFile*)sourcelist->First();
   first_source->cd(path);
   TDirectory *current_sourcedir = gDirectory;

   TChain *globChain = 0;
   TIter nextkey(current_sourcedir->GetListOfKeys());
   TKey *key;
   Bool_t success = kTRUE;

   // gain time, do not add the objects in the list in memory
   TH1::AddDirectory(kFALSE);

   while ((key = (TKey*) nextkey())) {
      first_source->cd(path);
      TObject *obj = key->ReadObj();

      if (obj->IsA()->InheritsFrom("TH1")) {
         Info("MergerMergeRecursive", "merging histogram %s", obj->GetName());
         TH1 *h1 = (TH1*)obj;

         TFile *nextsource = (TFile*)sourcelist->After(first_source);
         while (nextsource) {

            nextsource->cd(path);
            TH1 *h2 = (TH1*)gDirectory->Get(h1->GetName());
            if (h2) {
               h1->Add(h2);
               delete h2;
            }

            nextsource = (TFile*)sourcelist->After(nextsource);
         }
      } else if (obj->IsA()->InheritsFrom("TTree")) {
         Info("MergerMergeRecursive", "merging tree %s", obj->GetName());
         const char *obj_name= obj->GetName();

         globChain = new TChain(obj_name);
         globChain->Add(first_source->GetName());
         TFile *nextsource = (TFile*)sourcelist->After(first_source);
         while (nextsource) {
            globChain->Add(nextsource->GetName());
            nextsource = (TFile*)sourcelist->After(nextsource);
         }

      } else if (obj->IsA()->InheritsFrom("TDirectory")) {
         target->cd();
         TDirectory *newdir = target->mkdir(obj->GetName(), obj->GetTitle());
         if (!MergerMergeRecursive(newdir, sourcelist)) {
            Error("MergerMergeRecursive", "error during merge of directory %s",
                  newdir->GetPath());
            success = kFALSE;
         }
      } else {
         Error("MergerMergeRecursive", "unknown object type, name: %s title: %s",
               obj->GetName(), obj->GetTitle());
         success = kFALSE;
      }

      if (obj) {
         target->cd();

         if (obj->IsA()->InheritsFrom("TTree")) {
            globChain->Merge(target->GetFile() ,0, "keep");
            delete globChain;
         } else
            obj->Write(key->GetName());
      }

   }  // nextkey

   target->Write();

   TH1::AddDirectory(kTRUE);

   return success;
#endif
}
<|endoftext|>


<commit_before>/**
 * \file
 * \brief ContiguousRange template class header
 *
 * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef ESTD_CONTIGUOUSRANGE_HPP_
#define ESTD_CONTIGUOUSRANGE_HPP_

#include <array>

namespace estd
{

/**
 * \brief ContiguousRange template class is a pair of iterators to contiguous sequence of elements in memory.
 *
 * \tparam T is the type of data in the range
 */

template<typename T>
class ContiguousRange
{
public:

	/// value_type type
	using value_type = T;

	/// pointer type
	using pointer = value_type*;

	/// const_pointer type
	using const_pointer = const value_type*;

	/// reference type
	using reference = value_type&;

	/// const_reference type
	using const_reference = const value_type&;

	/// iterator type
	using iterator = value_type*;

	/// const_iterator type
	using const_iterator = const value_type*;

	/// size_type type
	using size_type = std::size_t;

	/// difference_type type
	using difference_type = std::ptrdiff_t;

	/// reverse_iterator type
	using reverse_iterator = std::reverse_iterator<iterator>;

	/// const_reverse_iterator type
	using const_reverse_iterator = std::reverse_iterator<const_iterator>;

	/**
	 * \brief ContiguousRange's constructor
	 *
	 * \param [in] beginn is an iterator to first element in the range
	 * \param [in] endd is an iterator to "one past the last" element in the range
	 */

	constexpr ContiguousRange(const iterator beginn, const iterator endd) noexcept :
			begin_{beginn},
			end_{endd}
	{

	}

	/**
	 * \brief Empty ContiguousRange's constructor
	 */

	constexpr ContiguousRange() noexcept :
			ContiguousRange{nullptr, nullptr}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using iterator and size
	 *
	 * \param [in] beginn is an iterator to first element in the range
	 * \param [in] sizee is the number of elements in the range
	 */

	constexpr ContiguousRange(const iterator beginn, size_t sizee) noexcept :
			begin_{beginn},
			end_{beginn + sizee}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using C-style array
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the array used to initialize the range
	 */

	template<size_t N>
	constexpr explicit ContiguousRange(T (& array)[N]) noexcept :
			ContiguousRange{array, array + N}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using std::array
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the array used to initialize the range
	 */

	template<size_t N>
	constexpr explicit ContiguousRange(std::array<T, N>& array) noexcept :
			ContiguousRange{array.begin(), array.end()}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using const std::array
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the const array used to initialize the range
	 */

	template<size_t N>
	constexpr explicit ContiguousRange(const std::array<typename std::remove_const<T>::type, N>& array) noexcept :
			ContiguousRange{array.begin(), array.end()}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using single value
	 *
	 * \param [in] value is a reference to variable used to initialize the range
	 */

	constexpr explicit ContiguousRange(T& value) noexcept :
			ContiguousRange{&value, &value + 1}
	{

	}

	/**
	 * \brief ContiguousRange's converting constructor
	 *
	 * This constructor is enabled only if \a T is \a const. It can be used to convert non-const range to const range.
	 *
	 * \param [in] other is a reference to source of conversion
	 */

	template<typename TT = T, typename = typename std::enable_if<std::is_const<TT>::value == true>::type>
	constexpr explicit ContiguousRange(const ContiguousRange<typename std::remove_const<TT>::type>& other) noexcept :
			ContiguousRange{other.begin(), other.end()}
	{

	}

	/**
	 * \brief ContiguousRange's subscript operator
	 *
	 * \param [in] i is the index of element that will be accessed
	 *
	 * \return reference to element at given index
	 */

	reference operator[](const size_type i) const noexcept
	{
		return begin_[i];
	}

	/**
	 * \return iterator to first element in the range
	 */

	constexpr iterator begin() const noexcept
	{
		return begin_;
	}

	/**
	 * \return const_iterator to first element in the range
	 */

	constexpr const_iterator cbegin() const noexcept
	{
		return begin();
	}

	/**
	 * \return const_iterator to "one past the last" element in the range
	 */

	constexpr const_iterator cend() const noexcept
	{
		return end();
	}

	/**
	 * \return const_reverse_iterator to first element in the reversed range (last element of the non-reversed range)
	 */

	constexpr const_reverse_iterator crbegin() const noexcept
	{
		return rbegin();
	}

	/**
	 * \return const_reverse_iterator to "one past the last" element in the reversed range ("one before the first"
	 * element of the non-reversed range)
	 */

	constexpr const_reverse_iterator crend() const noexcept
	{
		return rend();
	}

	/**
	 * \return iterator to "one past the last" element in the range
	 */

	constexpr iterator end() const noexcept
	{
		return end_;
	}

	/**
	 * \return reverse_iterator to first element in the reversed range (last element of the non-reversed range)
	 */

	constexpr reverse_iterator rbegin() const noexcept
	{
		return reverse_iterator{end()};
	}

	/**
	 * \return reverse_iterator to "one past the last" element in the reversed range ("one before the first" element of
	 * the non-reversed range)
	 */

	constexpr reverse_iterator rend() const noexcept
	{
		return reverse_iterator{begin()};
	}

	/**
	 * \return number of elements in the range
	 */

	constexpr size_type size() const noexcept
	{
		return end_ - begin_;
	}

private:

	/// iterator to first element in the range
	iterator begin_;

	/// iterator to "one past the last" element in the range
	iterator end_;
};

}	// namespace estd

#endif	// ESTD_CONTIGUOUSRANGE_HPP_
<commit_msg>Add another estd::ContiguousRange constructor overload<commit_after>/**
 * \file
 * \brief ContiguousRange template class header
 *
 * \author Copyright (C) 2014-2018 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef ESTD_CONTIGUOUSRANGE_HPP_
#define ESTD_CONTIGUOUSRANGE_HPP_

#include <array>

namespace estd
{

/**
 * \brief ContiguousRange template class is a pair of iterators to contiguous sequence of elements in memory.
 *
 * \tparam T is the type of data in the range
 */

template<typename T>
class ContiguousRange
{
public:

	/// value_type type
	using value_type = T;

	/// pointer type
	using pointer = value_type*;

	/// const_pointer type
	using const_pointer = const value_type*;

	/// reference type
	using reference = value_type&;

	/// const_reference type
	using const_reference = const value_type&;

	/// iterator type
	using iterator = value_type*;

	/// const_iterator type
	using const_iterator = const value_type*;

	/// size_type type
	using size_type = std::size_t;

	/// difference_type type
	using difference_type = std::ptrdiff_t;

	/// reverse_iterator type
	using reverse_iterator = std::reverse_iterator<iterator>;

	/// const_reverse_iterator type
	using const_reverse_iterator = std::reverse_iterator<const_iterator>;

	/**
	 * \brief ContiguousRange's constructor
	 *
	 * \param [in] beginn is an iterator to first element in the range
	 * \param [in] endd is an iterator to "one past the last" element in the range
	 */

	constexpr ContiguousRange(const iterator beginn, const iterator endd) noexcept :
			begin_{beginn},
			end_{endd}
	{

	}

	/**
	 * \brief Empty ContiguousRange's constructor
	 */

	constexpr ContiguousRange() noexcept :
			ContiguousRange{nullptr, nullptr}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using iterator and size
	 *
	 * \param [in] beginn is an iterator to first element in the range
	 * \param [in] sizee is the number of elements in the range
	 */

	constexpr ContiguousRange(const iterator beginn, size_t sizee) noexcept :
			begin_{beginn},
			end_{beginn + sizee}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using C-style array
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the array used to initialize the range
	 */

	template<size_t N>
	constexpr explicit ContiguousRange(T (& array)[N]) noexcept :
			ContiguousRange{array, array + N}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using std::array
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the array used to initialize the range
	 */

	template<size_t N>
	constexpr explicit ContiguousRange(std::array<T, N>& array) noexcept :
			ContiguousRange{array.begin(), array.end()}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using const std::array
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the const array used to initialize the range
	 */

	template<size_t N>
	constexpr explicit ContiguousRange(const std::array<typename std::remove_const<T>::type, N>& array) noexcept :
			ContiguousRange{array.begin(), array.end()}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using const std::array with const type
	 *
	 * This constructor is enabled only if \a T is \a const.
	 *
	 * \tparam N is the number of elements in the array
	 *
	 * \param [in] array is the array used to initialize the range
	 */

	template<size_t N, typename TT = T, typename = typename std::enable_if<std::is_const<TT>::value == true>::type>
	constexpr explicit ContiguousRange(const std::array<T, N>& array) noexcept :
			ContiguousRange{array.begin(), array.end()}
	{

	}

	/**
	 * \brief ContiguousRange's constructor using single value
	 *
	 * \param [in] value is a reference to variable used to initialize the range
	 */

	constexpr explicit ContiguousRange(T& value) noexcept :
			ContiguousRange{&value, &value + 1}
	{

	}

	/**
	 * \brief ContiguousRange's converting constructor
	 *
	 * This constructor is enabled only if \a T is \a const. It can be used to convert non-const range to const range.
	 *
	 * \param [in] other is a reference to source of conversion
	 */

	template<typename TT = T, typename = typename std::enable_if<std::is_const<TT>::value == true>::type>
	constexpr explicit ContiguousRange(const ContiguousRange<typename std::remove_const<TT>::type>& other) noexcept :
			ContiguousRange{other.begin(), other.end()}
	{

	}

	/**
	 * \brief ContiguousRange's subscript operator
	 *
	 * \param [in] i is the index of element that will be accessed
	 *
	 * \return reference to element at given index
	 */

	reference operator[](const size_type i) const noexcept
	{
		return begin_[i];
	}

	/**
	 * \return iterator to first element in the range
	 */

	constexpr iterator begin() const noexcept
	{
		return begin_;
	}

	/**
	 * \return const_iterator to first element in the range
	 */

	constexpr const_iterator cbegin() const noexcept
	{
		return begin();
	}

	/**
	 * \return const_iterator to "one past the last" element in the range
	 */

	constexpr const_iterator cend() const noexcept
	{
		return end();
	}

	/**
	 * \return const_reverse_iterator to first element in the reversed range (last element of the non-reversed range)
	 */

	constexpr const_reverse_iterator crbegin() const noexcept
	{
		return rbegin();
	}

	/**
	 * \return const_reverse_iterator to "one past the last" element in the reversed range ("one before the first"
	 * element of the non-reversed range)
	 */

	constexpr const_reverse_iterator crend() const noexcept
	{
		return rend();
	}

	/**
	 * \return iterator to "one past the last" element in the range
	 */

	constexpr iterator end() const noexcept
	{
		return end_;
	}

	/**
	 * \return reverse_iterator to first element in the reversed range (last element of the non-reversed range)
	 */

	constexpr reverse_iterator rbegin() const noexcept
	{
		return reverse_iterator{end()};
	}

	/**
	 * \return reverse_iterator to "one past the last" element in the reversed range ("one before the first" element of
	 * the non-reversed range)
	 */

	constexpr reverse_iterator rend() const noexcept
	{
		return reverse_iterator{begin()};
	}

	/**
	 * \return number of elements in the range
	 */

	constexpr size_type size() const noexcept
	{
		return end_ - begin_;
	}

private:

	/// iterator to first element in the range
	iterator begin_;

	/// iterator to "one past the last" element in the range
	iterator end_;
};

}	// namespace estd

#endif	// ESTD_CONTIGUOUSRANGE_HPP_
<|endoftext|>


<commit_before>#include <cstdlib>
#include <iostream>
#include <list>
#include <set>
#include <vector>

int g_capacity_a = 5;
int g_capacity_b = 3;
int g_target = 4;

struct State {
  State(int a, int b) : a(a), b(b), parent(NULL) {}

  int a;
  int b;
  const State* parent;

  bool operator<(const State& rhs) const {
    if (a == rhs.a) {
      return b < rhs.b;
    }
    return a < rhs.a;
  }
};

std::vector<State*> GetChildStates(const State& state) {
  std::vector<State*> child_states;

  // empty a
  if (state.a != 0) {
    child_states.push_back(new State(0, state.b));
  }

  // empty b
  if (state.b != 0) {
    child_states.push_back(new State(state.a, 0));
  }

  // pour a to b
  if (state.b < g_capacity_b && state.a > 0) {
    int transfer = state.a;
    int capacity = g_capacity_b - state.b;

    transfer = std::min(transfer, capacity);

    child_states.push_back(new State(state.a - transfer, state.b + transfer));
  }

  // pour b to a
  if (state.a < g_capacity_a && state.b > 0) {
    int transfer = state.b;
    int capacity = g_capacity_a - state.a;

    transfer = std::min(transfer, capacity);

    child_states.push_back(new State(state.a + transfer, state.b - transfer));
  }

  // fill a
  if (state.a < g_capacity_a) {
    child_states.push_back(new State(g_capacity_a, state.b));
  }

  // fill b
  if (state.b < g_capacity_b) {
    child_states.push_back(new State(state.a, g_capacity_b));
  }

  return child_states;
}

int main(int argc, const char* argv[]) {
  if (argc != 4) {
    std::cerr << "Usage: " << argv[0] << " <capacity-a> <capacity-b> <target>";
    return 1;
  }

  g_capacity_a = strtoul(argv[1], NULL, 10);
  g_capacity_b = strtoul(argv[2], NULL, 10);
  g_target = strtoul(argv[3], NULL, 10);

  std::vector<State*> states;
  std::set<State> visited_states;

  states.push_back(new State(0,0));
  while (states.size() > 0) {
    const State* state = states.back();
    states.pop_back();
    std::vector<State*> child_states = GetChildStates(*state);
    for (int i = 0; i < child_states.size(); ++i) {
      if (state->a + state->b == g_target) {
        // print path
        std::list<const State*> path;
        while (state != NULL) {
          path.push_front(state);
          state = state->parent;
        }
        for (std::list<const State*>::const_iterator path_it = path.begin();
             path_it != path.end(); ++path_it) {
          std::cout << (*path_it)->a << " " << (*path_it)->b << "\n";
        }
        return 0;
      }
      if (visited_states.count(*child_states[i]) == 0) {
        child_states[i]->parent = state;
        states.push_back(child_states[i]);
        visited_states.insert(*child_states[i]);
      }
    }
  }
  std::cout << "Failed to find a solution\n";
  return 1;
}
<commit_msg>Fix unsigned/signed mismatch<commit_after>#include <cstdlib>
#include <iostream>
#include <list>
#include <set>
#include <vector>

int g_capacity_a = 5;
int g_capacity_b = 3;
int g_target = 4;

struct State {
  State(int a, int b) : a(a), b(b), parent(NULL) {}

  int a;
  int b;
  const State* parent;

  bool operator<(const State& rhs) const {
    if (a == rhs.a) {
      return b < rhs.b;
    }
    return a < rhs.a;
  }
};

std::vector<State*> GetChildStates(const State& state) {
  std::vector<State*> child_states;

  // empty a
  if (state.a != 0) {
    child_states.push_back(new State(0, state.b));
  }

  // empty b
  if (state.b != 0) {
    child_states.push_back(new State(state.a, 0));
  }

  // pour a to b
  if (state.b < g_capacity_b && state.a > 0) {
    int transfer = state.a;
    int capacity = g_capacity_b - state.b;

    transfer = std::min(transfer, capacity);

    child_states.push_back(new State(state.a - transfer, state.b + transfer));
  }

  // pour b to a
  if (state.a < g_capacity_a && state.b > 0) {
    int transfer = state.b;
    int capacity = g_capacity_a - state.a;

    transfer = std::min(transfer, capacity);

    child_states.push_back(new State(state.a + transfer, state.b - transfer));
  }

  // fill a
  if (state.a < g_capacity_a) {
    child_states.push_back(new State(g_capacity_a, state.b));
  }

  // fill b
  if (state.b < g_capacity_b) {
    child_states.push_back(new State(state.a, g_capacity_b));
  }

  return child_states;
}

int main(int argc, const char* argv[]) {
  if (argc != 4) {
    std::cerr << "Usage: " << argv[0] << " <capacity-a> <capacity-b> <target>";
    return 1;
  }

  g_capacity_a = strtoul(argv[1], NULL, 10);
  g_capacity_b = strtoul(argv[2], NULL, 10);
  g_target = strtoul(argv[3], NULL, 10);

  std::vector<State*> states;
  std::set<State> visited_states;

  states.push_back(new State(0,0));
  while (states.size() > 0) {
    const State* state = states.back();
    states.pop_back();
    std::vector<State*> child_states = GetChildStates(*state);
    for (size_t i = 0; i < child_states.size(); ++i) {
      if (state->a + state->b == g_target) {
        // print path
        std::list<const State*> path;
        while (state != NULL) {
          path.push_front(state);
          state = state->parent;
        }
        for (std::list<const State*>::const_iterator path_it = path.begin();
             path_it != path.end(); ++path_it) {
          std::cout << (*path_it)->a << " " << (*path_it)->b << "\n";
        }
        return 0;
      }
      if (visited_states.count(*child_states[i]) == 0) {
        child_states[i]->parent = state;
        states.push_back(child_states[i]);
        visited_states.insert(*child_states[i]);
      }
    }
  }
  std::cout << "Failed to find a solution\n";
  return 1;
}
<|endoftext|>