<commit_before>//============================================================================
// include/vsmc/utility/rdtsc.hpp
//----------------------------------------------------------------------------
//
//                         vSMC: Scalable Monte Carlo
//
// This file is distributed under the 2-clauses BSD License.
// See LICENSE for details.
//============================================================================

#ifndef VSMC_UTILITY_RDTSC_HPP
#define VSMC_UTILITY_RDTSC_HPP

#include <vsmc/internal/common.hpp>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace vsmc {

/// \brief Return the TSC value using RDTSC instruction after synchronization
/// with CPUID instruction
/// \ingroup RDTSC
inline uint64_t rdtsc ()
{
#ifdef _MSC_VER
    int aux[4];
    __cpuidex(aux, 0, 0);

    return static_cast<uint64_t>(__rdtsc());
#else // _MSC_VER
    unsigned eax = 0;
    unsigned ecx = 0;
    unsigned edx = 0;
    __asm__ volatile
        (
         "cpuid\n\t"
         "rdtsc\n"
         : "=a" (eax), "=d" (edx)
         :  "a" (eax),  "c" (ecx)
        );

    return (static_cast<uint64_t>(edx) << 32) + static_cast<uint64_t>(eax);
#endif // _MSC_VER
}

/// \brief Return the TSC and TSC_AUX values using RDTSCP instruction
/// \ingroup RDTSC
inline uint64_t rdtscp (unsigned *aux)
{
#ifdef _MSC_VER
    return static_cast<uint64_t>(__rdtscp(aux));
#else // _MSC_VER
    unsigned eax = 0;
    unsigned edx = 0;
    unsigned ecx = 0;
    __asm__ volatile
        (
         "rdtscp\n"
         : "=a" (eax), "=c" (ecx), "=d" (edx)
        );
    *aux = ecx;

    return static_cast<uint64_t>(eax) + (static_cast<uint64_t>(edx) << 32);
#endif // _MSC_VER
}

/// \brief CPU clock cycle counter using RDTSC
/// \ingroup RDTSC
class RDTSCCounter
{
    public :

    RDTSCCounter () : elapsed_(0), start_(0), running_(false) {}

    /// \brief If the counter is running
    ///
    /// \details
    /// If `start()` has been called and no `stop()` call since, then it is
    /// running, otherwise it is stoped.
    bool running () const {return running_;}

    /// \brief Start the counter, no effect if already started
    ///
    /// \return `true` if it is started by this call, and the elapsed cycle
    /// count will be incremented next time `stop()` is called. The increment
    /// will be relative to the time point of this call. `false` if it is
    /// already started earlier.
    bool start ()
    {
        if (running_)
            return false;

        running_ = true;
        start_ = rdtsc();

        return true;
    }

    /// \brief Stop the counter, no effect if already stopped
    ///
    /// \return `true` if it is stoped by this call, and the elapsed cycle
    /// count has been incremented. `false` in one of the following situations.
    /// In all these situations, the elapsed cycle count will not be
    /// incremented.
    /// - It already stopped or wasn't started before.
    /// - The cycle count appears to decrease. This is most likely in the case
    /// that the TSC MSR has been reset.
    bool stop ()
    {
        if (!running_)
            return false;

        uint64_t stop = rdtsc();
        if (stop < start_)
            return false;

        elapsed_ += stop - start_;
        running_ = false;

        return true;
    }

    /// \brief Stop and reset the elapsed cycle count to zero
    void reset ()
    {
        elapsed_ = 0;
        running_ = false;
    }

    /// \brief Return the accumulated elapsed cycle count
    uint64_t cycles () const {return elapsed_;}

    private :

    uint64_t elapsed_;
    uint64_t start_;
    bool running_;
}; // class RDTSCCounter

/// \brief CPU clock cycle counter using RDTSCP
/// \ingroup RDTSC
///
/// \details
/// This class shall only be used if RDTSCP is supported. For example,
/// ~~~{.cpp}
/// RDTSCCouner c1;
/// RDTSCPCouner c2;
/// CPUID::has_feature<CPUIDFeatureExtRDTSCP>() ? c2.start() : c1.start();
/// ~~~
class RDTSCPCounter
{
    public :

    RDTSCPCounter () : elapsed_(0), start_(0), start_id_(0), running_(false) {}

    /// \brief If the counter is running
    ///
    /// \details
    /// If `start()` has been called and no `stop()` call since, then it is
    /// running, otherwise it is stoped.
    bool running () const {return running_;}

    /// \brief Start the counter, no effect if already started
    ///
    /// \return `true` if it is started by this call, and the elapsed cycle
    /// count will be incremented next time `stop()` is called. The increment
    /// will be relative to the time point of this call. `false` if it is
    /// already started earlier.
    bool start ()
    {
        if (running_)
            return false;

        running_ = true;
        start_ = rdtscp(&start_id_);

        return true;
    }

    /// \brief Stop the counter, no effect if already stopped
    ///
    /// \return `true` if it is stoped by this call, and the elapsed cycle
    /// count has been incremented. `false` in one of the following situations.
    /// In all these situations, the elapsed cycle count will not be
    /// incremented.
    /// - It already stopped or wasn't started before.
    /// - The logical processor has changed since the last successful `start()`
    /// call. The user is repsonsible for assure threads affinity.
    /// - The cycle count appears to decrease. This is most likely in the case
    /// that the TSC MSR has been reset.
    bool stop ()
    {
        if (!running_)
            return false;

        unsigned stop_id = 0;
        uint64_t stop = rdtscp(&stop_id);
        if (stop_id != start_id_ || stop < start_)
            return false;

        elapsed_ += stop - start_;
        running_ = false;

        return true;
    }

    /// \brief Stop and reset the elapsed cycle count to zero
    void reset ()
    {
        elapsed_ = 0;
        running_ = false;
    }

    /// \brief Return the accumulated elapsed cycle count
    uint64_t cycles () const {return elapsed_;}

    private :

    uint64_t elapsed_;
    uint64_t start_;
    unsigned start_id_;
    bool running_;
}; // class RDTSCPCounter

} // namespace vsmc

#endif // VSMC_UTILITY_RDTSC_HPP
<commit_msg>Fix RDTSC counter and remove sync by CPUID<commit_after>//============================================================================
// include/vsmc/utility/rdtsc.hpp
//----------------------------------------------------------------------------
//
//                         vSMC: Scalable Monte Carlo
//
// This file is distributed under the 2-clauses BSD License.
// See LICENSE for details.
//============================================================================

#ifndef VSMC_UTILITY_RDTSC_HPP
#define VSMC_UTILITY_RDTSC_HPP

#include <vsmc/internal/common.hpp>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace vsmc {

/// \brief Return the TSC value using RDTSC instruction
/// \ingroup RDTSC
inline uint64_t rdtsc ()
{
#ifdef _MSC_VER
    return static_cast<uint64_t>(__rdtsc());
#else // _MSC_VER
    unsigned eax = 0;
    unsigned edx = 0;
    __asm__ volatile
        (
         "rdtsc\n"
         : "=a" (eax), "=d" (edx)
        );

    return (static_cast<uint64_t>(edx) << 32) + static_cast<uint64_t>(eax);
#endif // _MSC_VER
}

/// \brief Return the TSC and TSC_AUX values using RDTSCP instruction
/// \ingroup RDTSC
inline uint64_t rdtscp (unsigned *aux)
{
#ifdef _MSC_VER
    return static_cast<uint64_t>(__rdtscp(aux));
#else // _MSC_VER
    unsigned eax = 0;
    unsigned ecx = 0;
    unsigned edx = 0;
    __asm__ volatile
        (
         "rdtscp\n"
         : "=a" (eax), "=c" (ecx), "=d" (edx)
        );
    *aux = ecx;

    return static_cast<uint64_t>(eax) + (static_cast<uint64_t>(edx) << 32);
#endif // _MSC_VER
}

/// \brief CPU clock cycle counter using RDTSC
/// \ingroup RDTSC
class RDTSCCounter
{
    public :

    RDTSCCounter () : elapsed_(0), start_(0), running_(false) {}

    /// \brief If the counter is running
    ///
    /// \details
    /// If `start()` has been called and no `stop()` call since, then it is
    /// running, otherwise it is stoped.
    bool running () const {return running_;}

    /// \brief Start the counter, no effect if already started
    ///
    /// \return `true` if it is started by this call, and the elapsed cycle
    /// count will be incremented next time `stop()` is called. The increment
    /// will be relative to the time point of this call. `false` if it is
    /// already started earlier.
    bool start ()
    {
        if (running_)
            return false;

        running_ = true;
        start_ = rdtsc();

        return true;
    }

    /// \brief Stop the counter, no effect if already stopped
    ///
    /// \return `true` if it is stoped by this call, and the elapsed cycle
    /// count has been incremented. `false` in one of the following situations.
    /// In all these situations, the elapsed cycle count will not be
    /// incremented.
    /// - It already stopped or wasn't started before.
    /// - The cycle count appears to decrease. This is most likely in the case
    /// that the TSC MSR has been reset.
    bool stop ()
    {
        if (!running_)
            return false;

        uint64_t stop = rdtsc();
        if (stop < start_)
            return false;

        elapsed_ += stop - start_;
        running_ = false;

        return true;
    }

    /// \brief Stop and reset the elapsed cycle count to zero
    void reset ()
    {
        elapsed_ = 0;
        running_ = false;
    }

    /// \brief Return the accumulated elapsed cycle count
    uint64_t cycles () const {return elapsed_;}

    private :

    uint64_t elapsed_;
    uint64_t start_;
    bool running_;
}; // class RDTSCCounter

/// \brief CPU clock cycle counter using RDTSCP
/// \ingroup RDTSC
///
/// \details
/// This class shall only be used if RDTSCP is supported. For example,
/// ~~~{.cpp}
/// RDTSCCouner c1;
/// RDTSCPCouner c2;
/// CPUID::has_feature<CPUIDFeatureExtRDTSCP>() ? c2.start() : c1.start();
/// ~~~
class RDTSCPCounter
{
    public :

    RDTSCPCounter () : elapsed_(0), start_(0), start_id_(0), running_(false) {}

    /// \brief If the counter is running
    ///
    /// \details
    /// If `start()` has been called and no `stop()` call since, then it is
    /// running, otherwise it is stoped.
    bool running () const {return running_;}

    /// \brief Start the counter, no effect if already started
    ///
    /// \return `true` if it is started by this call, and the elapsed cycle
    /// count will be incremented next time `stop()` is called. The increment
    /// will be relative to the time point of this call. `false` if it is
    /// already started earlier.
    bool start ()
    {
        if (running_)
            return false;

        running_ = true;
        start_ = rdtscp(&start_id_);

        return true;
    }

    /// \brief Stop the counter, no effect if already stopped
    ///
    /// \return `true` if it is stoped by this call, and the elapsed cycle
    /// count has been incremented. `false` in one of the following situations.
    /// In all these situations, the elapsed cycle count will not be
    /// incremented.
    /// - It already stopped or wasn't started before.
    /// - The logical processor has changed since the last successful `start()`
    /// call. The user is repsonsible for assure threads affinity.
    /// - The cycle count appears to decrease. This is most likely in the case
    /// that the TSC MSR has been reset.
    bool stop ()
    {
        if (!running_)
            return false;

        unsigned stop_id = 0;
        uint64_t stop = rdtscp(&stop_id);
        if (stop_id != start_id_ || stop < start_)
            return false;

        elapsed_ += stop - start_;
        running_ = false;

        return true;
    }

    /// \brief Stop and reset the elapsed cycle count to zero
    void reset ()
    {
        elapsed_ = 0;
        running_ = false;
    }

    /// \brief Return the accumulated elapsed cycle count
    uint64_t cycles () const {return elapsed_;}

    private :

    uint64_t elapsed_;
    uint64_t start_;
    unsigned start_id_;
    bool running_;
}; // class RDTSCPCounter

} // namespace vsmc

#endif // VSMC_UTILITY_RDTSC_HPP
<|endoftext|>


<commit_before>#pragma once

#include <gcl/mp/meta/functional.hpp>

namespace gcl::mp
{
    template <std::size_t index>
    struct type_index {};

    template <typename... types>
    struct tuple {

        constexpr static auto size = sizeof...(types);
        constexpr static auto empty = size == 0;

        constexpr tuple() requires(not empty)
            : storage{generate_storage(types{}...)}
        {}
        constexpr tuple(types&&... values)
            : storage{generate_storage(std::forward<decltype(values)>(values)...)}
        {}
        constexpr tuple(tuple&&) = default;

      private:
        // storage : by-pass missing features : auto non-static members, lambdas in unevaluated context
        /*static constexpr auto generate_storage(types&&... values)
        {
            return [&values...]<std::size_t... indexes>(std::index_sequence<indexes...>)
            {
                static_assert(sizeof...(indexes) == sizeof...(types));
                static_assert(sizeof...(indexes) == sizeof...(values));

                const auto generate_storage_entry = []<typename T, std::size_t index>(T && init_value) constexpr
                {
                    return [value = init_value](type_index<index>) mutable -> auto& { return value; };
                };
                return gcl::mp::meta::functional::overload{generate_storage_entry.template operator()<types, indexes>(
                    std::forward<decltype(values)>(values))...};
            }
            (std::make_index_sequence<sizeof...(types)>{});
        };*/
        static constexpr auto generate_storage(types&&... values)
        {
            const auto generate_storage_entry = []<typename T, std::size_t index>(T && init_value) constexpr
            {
                return [value = init_value](type_index<index>) mutable -> auto& { return value; };
            };

            #if defined(_MSC_VER) and not defined(__clang__)
            return [&]<std::size_t... indexes>(std::index_sequence<indexes...>)
            #else
            return [&generate_storage_entry, &values... ]<std::size_t... indexes>(std::index_sequence<indexes...>)
            #endif
            {
                static_assert(sizeof...(indexes) == sizeof...(types));
                static_assert(sizeof...(indexes) == sizeof...(values));

                return gcl::mp::meta::functional::overload{generate_storage_entry.template operator()<types, indexes>(
                    std::forward<decltype(values)>(values))...};
            }
            (std::make_index_sequence<sizeof...(types)>{});
        };
        decltype(generate_storage(types{}...)) storage;

        template <std::size_t index>
        struct type_at_impl { // defer symbol (Clang)
            using type = std::remove_reference_t<decltype(std::declval<tuple>().template get<index>())>;
        };

      public:
        template <std::size_t index>
        using type_at = typename type_at_impl<index>::type;

        template <std::size_t index>
        requires(not empty and index <= (size - 1)) constexpr auto& get()
        {
            return storage(type_index<index>{});
        }
        template <std::size_t index>
        requires(not empty and index <= (size - 1)) constexpr const auto& get() const
        {
            return const_cast<tuple*>(this)->get<index>(); // violate constness invariants
        }

        template <typename... arg_types>
        requires(sizeof...(arg_types) == size) constexpr bool operator==(const tuple<arg_types...>& other) const
        {
            return [ this, &other ]<std::size_t... indexes>(std::index_sequence<indexes...>)
            {
                return (((get<indexes>() == other.template get<indexes>()) && ...));
            }
            (std::make_index_sequence<size>{});
        }
    };
}

namespace gcl::mp::tests
{
    using namespace gcl::mp;

    using empty_tuple = tuple<>;
    using one_element_tuple = tuple<int>;
    using two_element_tuple = tuple<int, char>;

    static constexpr auto empty_tuple_default_init = empty_tuple{};

    //static constexpr auto one_element_tuple_default_init = one_element_tuple{};

    /*static constexpr auto one_element_tuple_values_init = one_element_tuple{42};
    static constexpr auto two_element_tuple_default_init = two_element_tuple{};
    static constexpr auto two_element_tuple_values_init = two_element_tuple{42, 'a'};

    static_assert(std::is_same_v<tuple<int, char>, decltype(tuple{42, 'a'})>);

    static_assert(std::is_same_v<two_element_tuple::type_at<0>, int>);
    static_assert(std::is_same_v<two_element_tuple::type_at<1>, char>);
    static_assert(std::is_same_v<decltype(std::declval<two_element_tuple>().get<0>()), int&>);
    static_assert(std::is_same_v<decltype(std::declval<const two_element_tuple&>().get<1>()), const char&>);*/
}<commit_msg>[mp/meta/tuple] : fix Clang, msvc-cl ICEs<commit_after>#pragma once

#include <gcl/mp/meta/functional.hpp>

namespace gcl::mp
{
    template <std::size_t index>
    struct type_index {};

    template <typename... types>
    struct tuple {

        constexpr static auto size = sizeof...(types);
        constexpr static auto empty = size == 0;

        constexpr tuple() requires(not empty)
            : storage{generate_storage(types{}...)}
        {}
        constexpr tuple(types&&... values)
            : storage{generate_storage(std::forward<decltype(values)>(values)...)}
        {}
        constexpr tuple(tuple&&) = default;

      private:
        // storage : by-pass missing features : auto non-static members, lambdas in unevaluated context
        using index_sequence = std::make_index_sequence<sizeof...(types)>;
        static constexpr auto generate_storage(types&&... values)
        { // defer parameter pack expansion (msvc-cl, Clang)
            return generate_storage_impl(index_sequence{}, std::forward<decltype(values)>(values)...);
        }
        template <std::size_t... indexes>
        static constexpr auto generate_storage_impl(std::index_sequence<indexes...>, types&&... values)
        {
            static_assert(sizeof...(indexes) == sizeof...(types));
            static_assert(sizeof...(indexes) == sizeof...(values));

            const auto generate_storage_entry = []<typename T, std::size_t index>(T && init_value) constexpr
            {
                return [value = init_value](type_index<index>) mutable -> auto& { return value; };
            };
            return gcl::mp::meta::functional::overload{
                generate_storage_entry.template operator()<types, indexes>(std::forward<decltype(values)>(values))...};
        };
        using storage_type = decltype(generate_storage(types{}...));
        storage_type storage;

        template <std::size_t index>
        struct type_at_impl { // defer symbol (Clang)
            using type = std::remove_reference_t<decltype(std::declval<tuple>().template get<index>())>;
        };

      public:
        template <std::size_t index>
        using type_at = typename type_at_impl<index>::type;

        template <std::size_t index>
        requires(not empty and index <= (size - 1)) constexpr auto& get()
        {
            return storage(type_index<index>{});
        }
        template <std::size_t index>
        requires(not empty and index <= (size - 1)) constexpr const auto& get() const
        {
            return const_cast<tuple*>(this)->get<index>(); // violate constness invariants
        }

        template <typename... arg_types>
        requires(sizeof...(arg_types) == size) constexpr bool operator==(const tuple<arg_types...>& other) const
        {
            return [ this, &other ]<std::size_t... indexes>(std::index_sequence<indexes...>)
            {
                return (((get<indexes>() == other.template get<indexes>()) && ...));
            }
            (std::make_index_sequence<size>{});
        }
    };
}

// When Clang, Msvc-cl gets better, replace `tuple::generate_storage` implementation by :
/*static constexpr auto generate_storage(types&&... values)
{
    return [&values...]<std::size_t... indexes>(std::index_sequence<indexes...>)
    {
        static_assert(sizeof...(indexes) == sizeof...(types));
        static_assert(sizeof...(indexes) == sizeof...(values));

        const auto generate_storage_entry = []<typename T, std::size_t index>(T && init_value) constexpr
        {
            return [value = init_value](type_index<index>) mutable -> auto& { return value; };
        };
        return gcl::mp::meta::functional::overload{generate_storage_entry.template operator()<types, indexes>(
            std::forward<decltype(values)>(values))...};
    }
    (std::make_index_sequence<sizeof...(types)>{});
};*/

namespace gcl::mp::tests
{
    using namespace gcl::mp;

    using empty_tuple = tuple<>;
    using one_element_tuple = tuple<int>;
    using two_element_tuple = tuple<int, char>;

    static constexpr auto empty_tuple_default_init = empty_tuple{};

    static constexpr auto one_element_tuple_default_init = one_element_tuple{};

    static constexpr auto one_element_tuple_values_init = one_element_tuple{42};
    static constexpr auto two_element_tuple_default_init = two_element_tuple{};
    static constexpr auto two_element_tuple_values_init = two_element_tuple{42, 'a'};

    static_assert(std::is_same_v<tuple<int, char>, decltype(tuple{42, 'a'})>);

    static_assert(std::is_same_v<two_element_tuple::type_at<0>, int>);
    static_assert(std::is_same_v<two_element_tuple::type_at<1>, char>);
    static_assert(std::is_same_v<decltype(std::declval<two_element_tuple>().get<0>()), int&>);
    static_assert(std::is_same_v<decltype(std::declval<const two_element_tuple&>().get<1>()), const char&>);
}<|endoftext|>


<commit_before>#pragma once

#include <new>
#include <memory>
#include <utility>
#include <uv.h>
#include <type_traits>
#include "error.hpp"

namespace uvw {

class Loop;

template<typename R>
class Handle {
    friend class Loop;

    template<typename... Args>
    explicit constexpr Handle(uv_loop_t *loop, Args&&... args)
        : res{std::make_shared<R>(loop, std::forward<Args>(args)...)}
    { }

public:
    constexpr Handle(const Handle &other): res{other.res} { }
    constexpr Handle(Handle &&other): res{std::move(other.res)} { }

    constexpr void operator=(const Handle &other) { res = other.res; }
    constexpr void operator=(Handle &&other) { res = std::move(other.res); }

    constexpr operator R&() noexcept { return *res; }
    operator const R&() const noexcept { return *res; }

private:
    std::shared_ptr<R> res;
};

class Loop final {
public:
    Loop(bool def = true)
        : loop{def ? uv_default_loop() : new uv_loop_t, [def](uv_loop_t *l){ if(!def) delete l; }}
    {
        if(!def) {
            auto err = uv_loop_init(loop.get());

            if(err) {
                throw UVWException{err};
            }
        } else if(!loop) {
            throw std::bad_alloc{};
        }
    }

    Loop(const Loop &) = delete;
    Loop(Loop &&other) = delete;
    Loop& operator=(const Loop &) = delete;
    Loop& operator=(Loop &&other) = delete;

    ~Loop() {
        if(loop) {
            close();
        }
    }

    template<typename R, typename... Args>
    Handle<R> handle(Args&&... args) {
        return Handle<R>{loop.get(), std::forward<Args>(args)...};
    }

    bool close() noexcept {
        return (uv_loop_close(loop.get()) == 0);
    }

    bool run() noexcept {
        return (uv_run(loop.get(), UV_RUN_DEFAULT) == 0);
    }

    bool runOnce() noexcept {
        return (uv_run(loop.get(), UV_RUN_ONCE) == 0);
    }

    bool runWait() noexcept {
        return (uv_run(loop.get(), UV_RUN_NOWAIT) == 0);
    }

    bool alive() const noexcept {
        return !(uv_loop_alive(loop.get()) == 0);
    }

    void stop() noexcept {
        uv_stop(loop.get());
    }

private:
    using Deleter = std::function<void(uv_loop_t *)>;
    std::unique_ptr<uv_loop_t, Deleter> loop;
};

}
<commit_msg>clean up<commit_after>#pragma once

#include <new>
#include <memory>
#include <utility>
#include <uv.h>
#include "error.hpp"

namespace uvw {

class Loop;

template<typename R>
class Handle {
    friend class Loop;

    template<typename... Args>
    explicit constexpr Handle(uv_loop_t *loop, Args&&... args)
        : res{std::make_shared<R>(loop, std::forward<Args>(args)...)}
    { }

public:
    constexpr Handle(const Handle &other): res{other.res} { }
    constexpr Handle(Handle &&other): res{std::move(other.res)} { }

    constexpr void operator=(const Handle &other) { res = other.res; }
    constexpr void operator=(Handle &&other) { res = std::move(other.res); }

    constexpr operator R&() noexcept { return *res; }
    operator const R&() const noexcept { return *res; }

private:
    std::shared_ptr<R> res;
};

class Loop final {
public:
    Loop(bool def = true)
        : loop{def ? uv_default_loop() : new uv_loop_t, [def](uv_loop_t *l){ if(!def) delete l; }}
    {
        if(!def) {
            auto err = uv_loop_init(loop.get());

            if(err) {
                throw UVWException{err};
            }
        } else if(!loop) {
            throw std::bad_alloc{};
        }
    }

    Loop(const Loop &) = delete;
    Loop(Loop &&other) = delete;
    Loop& operator=(const Loop &) = delete;
    Loop& operator=(Loop &&other) = delete;

    ~Loop() {
        if(loop) {
            close();
        }
    }

    template<typename R, typename... Args>
    Handle<R> handle(Args&&... args) {
        return Handle<R>{loop.get(), std::forward<Args>(args)...};
    }

    bool close() noexcept {
        return (uv_loop_close(loop.get()) == 0);
    }

    bool run() noexcept {
        return (uv_run(loop.get(), UV_RUN_DEFAULT) == 0);
    }

    bool runOnce() noexcept {
        return (uv_run(loop.get(), UV_RUN_ONCE) == 0);
    }

    bool runWait() noexcept {
        return (uv_run(loop.get(), UV_RUN_NOWAIT) == 0);
    }

    bool alive() const noexcept {
        return !(uv_loop_alive(loop.get()) == 0);
    }

    void stop() noexcept {
        uv_stop(loop.get());
    }

private:
    using Deleter = std::function<void(uv_loop_t *)>;
    std::unique_ptr<uv_loop_t, Deleter> loop;
};

}
<|endoftext|>


<commit_before>#include <iostream>
#include <boost/lexical_cast.hpp>
#include <bitcoin/bitcoin.hpp>
#include "util.hpp"

using namespace bc;

bool validsig(transaction_type& tx, size_t input_index,
    elliptic_curve_key& key, const script_type& script_code,
    data_chunk signature)
{
    uint32_t hash_type = 0;
    hash_type = signature.back();
    signature.pop_back();

    hash_digest tx_hash =
        script_type::generate_signature_hash(
            tx, input_index, script_code, hash_type);
    return key.verify(tx_hash, signature);
}

int main(int argc, char** argv)
{
    if (argc != 5)
    {
        std::cerr << "Usage: sign-input FILENAME N SCRIPT_CODE SIGNATURE" << std::endl;
        return -1;
    }
    const std::string filename = argv[1];
    transaction_type tx;
    if (!load_tx(tx, filename))
        return -1;
    const std::string index_str = argv[2];
    size_t input_index;
    try
    {
        input_index = boost::lexical_cast<size_t>(index_str);
    }
    catch (const boost::bad_lexical_cast&)
    {
        std::cerr << "sign-input: Bad N provided." << std::endl;
        return -1;
    }
    const script_type script_code = parse_script(decode_hex(argv[3]));
    if (input_index >= tx.inputs.size())
    {
        std::cerr << "sign-input: N out of range." << std::endl;
        return -1;
    }
    const data_chunk signature = decode_hex(argv[4]);
    elliptic_curve_key key;
    if (!read_public_or_private_key(key))
        return -1;
    if (!validsig(tx, input_index, key, script_code, signature))
    {
        std::cout << "Status: Failed" << std::endl;
        return 0;
    }
    std::cout << "Status: OK" << std::endl;
    return 0;
}

<commit_msg>Fix validsig usage and error messages.<commit_after>#include <iostream>
#include <boost/lexical_cast.hpp>
#include <bitcoin/bitcoin.hpp>
#include "util.hpp"

using namespace bc;

bool validsig(transaction_type& tx, size_t input_index,
    elliptic_curve_key& key, const script_type& script_code,
    data_chunk signature)
{
    uint32_t hash_type = 0;
    hash_type = signature.back();
    signature.pop_back();

    hash_digest tx_hash =
        script_type::generate_signature_hash(
            tx, input_index, script_code, hash_type);
    return key.verify(tx_hash, signature);
}

int main(int argc, char** argv)
{
    if (argc != 5)
    {
        std::cerr << "Usage: validsig FILENAME N SCRIPT_CODE SIGNATURE" << std::endl;
        return -1;
    }
    const std::string filename = argv[1];
    transaction_type tx;
    if (!load_tx(tx, filename))
        return -1;
    const std::string index_str = argv[2];
    size_t input_index;
    try
    {
        input_index = boost::lexical_cast<size_t>(index_str);
    }
    catch (const boost::bad_lexical_cast&)
    {
        std::cerr << "validsig: Bad N provided." << std::endl;
        return -1;
    }
    const script_type script_code = parse_script(decode_hex(argv[3]));
    if (input_index >= tx.inputs.size())
    {
        std::cerr << "validsig: N out of range." << std::endl;
        return -1;
    }
    const data_chunk signature = decode_hex(argv[4]);
    elliptic_curve_key key;
    if (!read_public_or_private_key(key))
        return -1;
    if (!validsig(tx, input_index, key, script_code, signature))
    {
        std::cout << "Status: Failed" << std::endl;
        return 0;
    }
    std::cout << "Status: OK" << std::endl;
    return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <sync.h>
#include <clientversion.h>
#include <util.h>
#include <warnings.h>

CCriticalSection cs_warnings;
std::string strMiscWarning;
bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false;

void SetMiscWarning(const std::string& strWarning)
{
    LOCK(cs_warnings);
    strMiscWarning = strWarning;
}

void SetfLargeWorkForkFound(bool flag)
{
    LOCK(cs_warnings);
    fLargeWorkForkFound = flag;
}

bool GetfLargeWorkForkFound()
{
    LOCK(cs_warnings);
    return fLargeWorkForkFound;
}

void SetfLargeWorkInvalidChainFound(bool flag)
{
    LOCK(cs_warnings);
    fLargeWorkInvalidChainFound = flag;
}

std::string GetWarnings(const std::string& strFor)
{
    std::string strStatusBar;
    std::string strGUI;
    const std::string uiAlertSeperator = "
";

    LOCK(cs_warnings);

    if (!CLIENT_VERSION_IS_RELEASE) {
        strStatusBar = "This is a pre-release test build - use at your own risk - do not use for privatesend, mining or merchant applications";
        strGUI = _("This is a pre-release test build - use at your own risk - do not use for privatesend, mining or merchant applications");
    }

    // Misc warnings like out of disk space and clock is wrong
    if (strMiscWarning != "")
    {
        strStatusBar = strMiscWarning;
        strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
    }

    if (fLargeWorkForkFound)
    {
        strStatusBar = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
        strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
    }
    else if (fLargeWorkInvalidChainFound)
    {
        strStatusBar = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
        strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
    }

    if (strFor == "gui")
        return strGUI;
    else if (strFor == "statusbar")
        return strStatusBar;
    assert(!"GetWarnings(): invalid parameter");
    return "error";
}
<commit_msg>Add Clang thread safety annotations for variables guarded by cs_warnings<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <sync.h>
#include <clientversion.h>
#include <util.h>
#include <warnings.h>

CCriticalSection cs_warnings;
std::string strMiscWarning GUARDED_BY(cs_warnings);
bool fLargeWorkForkFound GUARDED_BY(cs_warnings) = false;
bool fLargeWorkInvalidChainFound GUARDED_BY(cs_warnings) = false;

void SetMiscWarning(const std::string& strWarning)
{
    LOCK(cs_warnings);
    strMiscWarning = strWarning;
}

void SetfLargeWorkForkFound(bool flag)
{
    LOCK(cs_warnings);
    fLargeWorkForkFound = flag;
}

bool GetfLargeWorkForkFound()
{
    LOCK(cs_warnings);
    return fLargeWorkForkFound;
}

void SetfLargeWorkInvalidChainFound(bool flag)
{
    LOCK(cs_warnings);
    fLargeWorkInvalidChainFound = flag;
}

std::string GetWarnings(const std::string& strFor)
{
    std::string strStatusBar;
    std::string strGUI;
    const std::string uiAlertSeperator = "
";

    LOCK(cs_warnings);

    if (!CLIENT_VERSION_IS_RELEASE) {
        strStatusBar = "This is a pre-release test build - use at your own risk - do not use for privatesend, mining or merchant applications";
        strGUI = _("This is a pre-release test build - use at your own risk - do not use for privatesend, mining or merchant applications");
    }

    // Misc warnings like out of disk space and clock is wrong
    if (strMiscWarning != "")
    {
        strStatusBar = strMiscWarning;
        strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
    }

    if (fLargeWorkForkFound)
    {
        strStatusBar = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
        strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
    }
    else if (fLargeWorkInvalidChainFound)
    {
        strStatusBar = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
        strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
    }

    if (strFor == "gui")
        return strGUI;
    else if (strFor == "statusbar")
        return strStatusBar;
    assert(!"GetWarnings(): invalid parameter");
    return "error";
}
<|endoftext|>


<commit_before>/*************************************************
* ANSI X9.31 RNG Source File                     *
* (C) 1999-2007 Jack Lloyd                       *
*************************************************/

#include <botan/x931_rng.h>
#include <botan/lookup.h>
#include <botan/randpool.h>
#include <botan/bit_ops.h>
#include <algorithm>

namespace Botan {

/*************************************************
* Generate a buffer of random bytes              *
*************************************************/
void ANSI_X931_RNG::randomize(byte out[], u32bit length) throw(PRNG_Unseeded)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   while(length)
      {
      const u32bit copied = std::min(length, R.size() - position);

      copy_mem(out, R + position, copied);
      out += copied;
      length -= copied;
      position += copied;

      if(position == R.size())
         update_buffer();
      }
   }

/*************************************************
* Refill the internal state                      *
*************************************************/
void ANSI_X931_RNG::update_buffer()
   {
   const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE;

   SecureVector<byte> DT(BLOCK_SIZE);

   prng->randomize(DT, DT.size());
   cipher->encrypt(DT);

   xor_buf(R, V, DT, BLOCK_SIZE);
   cipher->encrypt(R);

   xor_buf(V, R, DT, BLOCK_SIZE);
   cipher->encrypt(V);

   position = 0;
   }

/*************************************************
* Add entropy to internal state                  *
*************************************************/
void ANSI_X931_RNG::add_randomness(const byte data[], u32bit length)
   {
   prng->add_entropy(data, length);

   if(is_seeded())
      {
      SecureVector<byte> key(cipher->MAXIMUM_KEYLENGTH);
      prng->randomize(key, key.size());
      cipher->set_key(key, key.size());

      prng->randomize(V, V.size());

      update_buffer();
      }
   }

/*************************************************
* Check if the the PRNG is seeded                *
*************************************************/
bool ANSI_X931_RNG::is_seeded() const
   {
   return prng->is_seeded();
   }

/*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void ANSI_X931_RNG::clear() throw()
   {
   cipher->clear();
   prng->clear();
   R.clear();
   V.clear();

   position = 0;
   }

/*************************************************
* Return the name of this type                   *
*************************************************/
std::string ANSI_X931_RNG::name() const
   {
   return "X9.31(" + cipher->name() + ")";
   }

/*************************************************
* ANSI X931 RNG Constructor                      *
*************************************************/
ANSI_X931_RNG::ANSI_X931_RNG(const std::string& cipher_name,
                             RandomNumberGenerator* prng_ptr)
   {
   if(!prng_ptr)
      throw Invalid_Argument("ANSI_X931_RNG constructor: NULL prng");

   prng = prng_ptr;
   cipher = get_block_cipher(cipher_name);

   const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE;

   V.create(BLOCK_SIZE);
   R.create(BLOCK_SIZE);

   position = 0;
   }

/*************************************************
* ANSI X931 RNG Destructor                       *
*************************************************/
ANSI_X931_RNG::~ANSI_X931_RNG()
   {
   delete cipher;
   delete prng;
   }

}
<commit_msg>Change how the ANSI X9.31 generator tells that it is seeded. Previously, it was seeded if and only if the underlying PRNG was seeded. However if the PRNG always returned as being seeded, we would never generate a V value, etc (leaving them at the default zero). This would not occur with any of Botan's built in PRNGs since their implementations require that add_randomness be called at least once before is_seeded will return true. However this is not an invariant of the general RandomNumberGenerator interface.<commit_after>/*************************************************
* ANSI X9.31 RNG Source File                     *
* (C) 1999-2007 Jack Lloyd                       *
*************************************************/

#include <botan/x931_rng.h>
#include <botan/lookup.h>
#include <botan/randpool.h>
#include <botan/bit_ops.h>
#include <algorithm>

namespace Botan {

/*************************************************
* Generate a buffer of random bytes              *
*************************************************/
void ANSI_X931_RNG::randomize(byte out[], u32bit length) throw(PRNG_Unseeded)
   {
   if(!is_seeded())
      throw PRNG_Unseeded(name());

   while(length)
      {
      if(position == R.size())
         update_buffer();

      const u32bit copied = std::min(length, R.size() - position);

      copy_mem(out, R + position, copied);
      out += copied;
      length -= copied;
      position += copied;
      }
   }

/*************************************************
* Refill the internal state                      *
*************************************************/
void ANSI_X931_RNG::update_buffer()
   {
   SecureVector<byte> DT(cipher->BLOCK_SIZE);

   prng->randomize(DT, DT.size());
   cipher->encrypt(DT);

   xor_buf(R, V, DT, cipher->BLOCK_SIZE);
   cipher->encrypt(R);

   xor_buf(V, R, DT, cipher->BLOCK_SIZE);
   cipher->encrypt(V);

   position = 0;
   }

/*************************************************
* Add entropy to internal state                  *
*************************************************/
void ANSI_X931_RNG::add_randomness(const byte data[], u32bit length)
   {
   prng->add_entropy(data, length);

   if(prng->is_seeded())
      {
      SecureVector<byte> key(cipher->MAXIMUM_KEYLENGTH);
      prng->randomize(key, key.size());
      cipher->set_key(key, key.size());

      if(V.size() != cipher->BLOCK_SIZE)
         V.create(cipher->BLOCK_SIZE);
      prng->randomize(V, V.size());

      update_buffer();
      }
   }

/*************************************************
* Check if the the PRNG is seeded                *
*************************************************/
bool ANSI_X931_RNG::is_seeded() const
   {
   return V.has_items();
   }

/*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void ANSI_X931_RNG::clear() throw()
   {
   cipher->clear();
   prng->clear();
   R.clear();
   V.clear();

   position = 0;
   }

/*************************************************
* Return the name of this type                   *
*************************************************/
std::string ANSI_X931_RNG::name() const
   {
   return "X9.31(" + cipher->name() + ")";
   }

/*************************************************
* ANSI X931 RNG Constructor                      *
*************************************************/
ANSI_X931_RNG::ANSI_X931_RNG(const std::string& cipher_name,
                             RandomNumberGenerator* prng_ptr)
   {
   if(!prng_ptr)
      throw Invalid_Argument("ANSI_X931_RNG constructor: NULL prng");

   prng = prng_ptr;
   cipher = get_block_cipher(cipher_name);

   R.create(cipher->BLOCK_SIZE);
   position = 0;
   }

/*************************************************
* ANSI X931 RNG Destructor                       *
*************************************************/
ANSI_X931_RNG::~ANSI_X931_RNG()
   {
   delete cipher;
   delete prng;
   }

}
<|endoftext|>


<commit_before>#ifndef IMAGE_MANAGER_HPP_INCLUDED
#define IMAGE_MANAGER_HPP_INCLUDED

#include <boost/shared_ptr.hpp>

struct ImageType
{
   int shmid;
   unsigned char *shmaddr;
   double time;
};

struct ConvertedImage;

class ImageManager
{
public:
   static boost::shared_ptr<ImageManager> create(int width, int height);
   virtual boost::shared_ptr<ImageType> getImage() = 0;

   virtual boost::shared_ptr<ConvertedImage> getConvertedImage() =0;

protected:
   ~ImageManager()
   {}
};

#endif
<commit_msg>Spacing<commit_after>#ifndef IMAGE_MANAGER_HPP_INCLUDED
#define IMAGE_MANAGER_HPP_INCLUDED

#include <boost/shared_ptr.hpp>

struct ImageType
{
   int shmid;
   unsigned char *shmaddr;
   double time;
};

struct ConvertedImage;

class ImageManager
{
public:
   static boost::shared_ptr<ImageManager> create(int width, int height);

   virtual boost::shared_ptr<ImageType> getImage() = 0;
   virtual boost::shared_ptr<ConvertedImage> getConvertedImage() =0;

protected:
   ~ImageManager()
   {}
};

#endif
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated nodeation 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.
*/

#include "flusspferd/xml/node.hpp"
#include "flusspferd/xml/document.hpp"
#include "flusspferd/string.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/tracer.hpp"
#include "flusspferd/exception.hpp"
#include "flusspferd/local_root_scope.hpp"

using namespace flusspferd;
using namespace flusspferd::xml;

object node::create(xmlNodePtr ptr) {
  if (ptr->_private)
    return value::from_permanent_ptr(ptr->_private).to_object();

  switch (ptr->type) {
  case XML_DOCUMENT_NODE:
    return create_native_object<document>(object(), xmlDocPtr(ptr));
  default:
    return create_native_object<node>(object(), ptr);
  }
}

xmlNodePtr node::c_from_js(object const &obj) {
  if (!obj.is_valid())
    return 0;
  try {
    xml::node *p = dynamic_cast<xml::node*>(native_object_base::get_native(obj));
    if (!p)
      return 0;
    return p->c_obj();
  } catch (std::exception&) {
    return 0;
  }
}

node::node(xmlNodePtr ptr)
  : ptr(ptr)
{
  ptr->_private = permanent_ptr();
}

node::node(call_context &x) {
  local_root_scope scope;

  string name(x.arg[0]);

  ptr = xmlNewNode(0, (xmlChar const *) name.c_str());

  if (!ptr)
    throw exception("Could not create XML node");

  ptr->_private = permanent_ptr();
}

node::~node() {
  if (ptr && !ptr->parent && ptr->_private == permanent_ptr()) {
    xmlFreeNode(ptr);
  }
}

void node::post_initialize() {
  ptr->_private = permanent_ptr();

  register_native_method("copy", &node::copy);

  define_native_property("name", permanent_property, &node::prop_name);
  define_native_property("lang", permanent_property, &node::prop_lang);
  define_native_property("parent", permanent_property, &node::prop_parent);
  define_native_property("next", permanent_property, &node::prop_next);
  define_native_property(
    "document", permanent_property | read_only_property, &node::prop_document);
  define_native_property(
    "type", permanent_property | read_only_property, &node::prop_type);
}

object node::class_info::create_prototype() {
  object proto = create_object();

  create_native_method(proto, "copy", 1);

  return proto;
}

char const *node::class_info::constructor_name() {
  return "Node";
}

std::size_t node::class_info::constructor_arity() {
  return 1;
}

static void trace_children(tracer &trc, xmlNodePtr ptr) {
  while (ptr) {
    trc("node-children", value::from_permanent_ptr(ptr->_private));
    trace_children(trc, ptr->children);
    ptr = ptr->next;
  }
}

static void trace_parents(tracer &trc, xmlNodePtr ptr) {
  while (ptr) {
    trc("node-parent", value::from_permanent_ptr(ptr->_private));
    ptr = ptr->parent;
  }
}

void node::trace(tracer &trc) {
  trc("node-self", value::from_permanent_ptr(ptr->_private));

  trace_children(trc, ptr->children);
  trace_parents(trc, ptr->parent);

  if (ptr->doc)
    trc("node-doc", value::from_permanent_ptr(ptr->doc->_private));

  if (ptr->next)
    trc("node-next", value::from_permanent_ptr(ptr->next->_private));

  if (ptr->prev)
    trc("node-prev", value::from_permanent_ptr(ptr->prev->_private));
}

void node::prop_name(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    if (!ptr->name)
      data = value();
    else
      data = string((char const *) ptr->name);
    break;
  case property_set:
    xmlNodeSetName(ptr, (xmlChar const *) data.to_string().c_str());
    break;
  default: break;
  };
}

void node::prop_lang(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    {
      xmlChar const *lang = xmlNodeGetLang(ptr);
      if (!lang)
        data = value();
      else
        data = string((char const *) lang);
    }
    break;
  case property_set:
    xmlNodeSetLang(ptr, (xmlChar const *) data.to_string().c_str());
    break;
  default: break;
  };
}

void node::prop_parent(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    if (!ptr->parent)
      data = object();
    else
      data = create(ptr->parent);
    break;
  case property_set:
    if (data.is_void() || data.is_null()) {
      xmlUnlinkNode(ptr);
      data = object();
    } else if (!data.is_object()) {
      data = value();
    } else {
      xmlNodePtr parent = c_from_js(data.get_object());
      if (!parent) {
        data = value();
        break;
      }
      if (ptr->parent)
        xmlUnlinkNode(ptr);
      xmlAddChild(parent, ptr);
    }
    break;
  default: break;
  }
}

void node::prop_next(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    if (!ptr->parent)
      data = object();
    else
      data = create(ptr->next);
    break;
  case property_set:
    if (data.is_void() || data.is_null()) {
      ptr->next = 0;
      data = object();
    } else if (!data.is_object()) {
      data = value();
    } else {
      xmlNodePtr next = c_from_js(data.get_object());
      if (!next) {
        data = value();
        break;
      }
      ptr->next = next;
      while (next) {
        next->parent = ptr->parent;
        if (!next->next)
          next->parent->last = next;
        next = next->next;
      }
      xmlSetListDoc(ptr->next, ptr->doc);
    }
    break;
  default: break;
  }
}

void node::prop_document(property_mode mode, value &data) {
  if (mode != property_get)
    return;

  if (!ptr->doc)
    data = object();
  else
    data = create(xmlNodePtr(ptr->doc));
}

void node::prop_type(property_mode mode, value &data) {
  if (mode != property_get)
    return;

  switch (ptr->type) {
  case XML_ELEMENT_NODE:
    data = string("ELEMENT");
    break;
  case XML_ATTRIBUTE_NODE:
    data = string("ATTRIBUTE");
    break;
  case XML_TEXT_NODE:
    data = string("TEXT");
    break;
  case XML_CDATA_SECTION_NODE:
    data = string("CDATA-SECTION");
    break;
  case XML_ENTITY_REF_NODE:
    data = string("ENTITY-REFERENCE");
    break;
  case XML_ENTITY_NODE:
    data = string("ENTITY");
    break;
  case XML_PI_NODE:
    data = string("PI");
    break;
  case XML_COMMENT_NODE:
    data = string("COMMENT");
    break;
  case XML_DOCUMENT_NODE:
    data = string("DOCUMENT");
    break;
  case XML_DOCUMENT_TYPE_NODE:
    data = string("DOCUMENT-TYPE");
    break;
  case XML_DOCUMENT_FRAG_NODE:
    data = string("DOCUMENT-FRAGMENT");
    break;
  case XML_NOTATION_NODE:
    data = string("NOTATION");
    break;
  case XML_HTML_DOCUMENT_NODE:
    data = string("HTML-DOCUMENT");
    break;
  case XML_DTD_NODE:
    data = string("DTD");
    break;
  case XML_ELEMENT_DECL:
    data = string("ELEMENT-DECLARATION");
    break;
  case XML_ATTRIBUTE_DECL:
    data = string("ATTRIBUTE-DECLARATION");
    break;
  case XML_ENTITY_DECL:
    data = string("ENTITY-DECLARATION");
    break;
  case XML_NAMESPACE_DECL:
    data = string("NAMESPACE-DECLARATION");
    break;
  case XML_XINCLUDE_START:
    data = string("XINCLUDE-START");
    break;
  case XML_XINCLUDE_END:
    data = string("XINCLUDE-END");
    break;
  default:
    data = string("OTHER");
    break;
  }
}

object node::copy(bool recursive) {
  xmlNodePtr copy = xmlCopyNode(ptr, recursive);

  if (!copy)
    throw exception("Could not copy XML node");

  return create(copy);
}

<commit_msg>simplify<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated nodeation 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.
*/

#include "flusspferd/xml/node.hpp"
#include "flusspferd/xml/document.hpp"
#include "flusspferd/string.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/tracer.hpp"
#include "flusspferd/exception.hpp"
#include "flusspferd/local_root_scope.hpp"

using namespace flusspferd;
using namespace flusspferd::xml;

object node::create(xmlNodePtr ptr) {
  if (ptr->_private)
    return from_permanent_ptr(ptr->_private);

  switch (ptr->type) {
  case XML_DOCUMENT_NODE:
    return create_native_object<document>(object(), xmlDocPtr(ptr));
  default:
    return create_native_object<node>(object(), ptr);
  }
}

xmlNodePtr node::c_from_js(object const &obj) {
  if (!obj.is_valid())
    return 0;
  try {
    xml::node *p = dynamic_cast<xml::node*>(native_object_base::get_native(obj));
    if (!p)
      return 0;
    return p->c_obj();
  } catch (std::exception&) {
    return 0;
  }
}

node::node(xmlNodePtr ptr)
  : ptr(ptr)
{
  ptr->_private = permanent_ptr();
}

node::node(call_context &x) {
  local_root_scope scope;

  string name(x.arg[0]);

  ptr = xmlNewNode(0, (xmlChar const *) name.c_str());

  if (!ptr)
    throw exception("Could not create XML node");

  ptr->_private = permanent_ptr();
}

node::~node() {
  if (ptr && !ptr->parent && ptr->_private == permanent_ptr()) {
    xmlFreeNode(ptr);
  }
}

void node::post_initialize() {
  ptr->_private = permanent_ptr();

  register_native_method("copy", &node::copy);

  define_native_property("name", permanent_property, &node::prop_name);
  define_native_property("lang", permanent_property, &node::prop_lang);
  define_native_property("parent", permanent_property, &node::prop_parent);
  define_native_property("next", permanent_property, &node::prop_next);
  define_native_property(
    "document", permanent_property | read_only_property, &node::prop_document);
  define_native_property(
    "type", permanent_property | read_only_property, &node::prop_type);
}

object node::class_info::create_prototype() {
  object proto = create_object();

  create_native_method(proto, "copy", 1);

  return proto;
}

char const *node::class_info::constructor_name() {
  return "Node";
}

std::size_t node::class_info::constructor_arity() {
  return 1;
}

static void trace_children(tracer &trc, xmlNodePtr ptr) {
  while (ptr) {
    trc("node-children", value::from_permanent_ptr(ptr->_private));
    trace_children(trc, ptr->children);
    ptr = ptr->next;
  }
}

static void trace_parents(tracer &trc, xmlNodePtr ptr) {
  while (ptr) {
    trc("node-parent", value::from_permanent_ptr(ptr->_private));
    ptr = ptr->parent;
  }
}

void node::trace(tracer &trc) {
  trc("node-self", value::from_permanent_ptr(ptr->_private));

  trace_children(trc, ptr->children);
  trace_parents(trc, ptr->parent);

  if (ptr->doc)
    trc("node-doc", value::from_permanent_ptr(ptr->doc->_private));

  if (ptr->next)
    trc("node-next", value::from_permanent_ptr(ptr->next->_private));

  if (ptr->prev)
    trc("node-prev", value::from_permanent_ptr(ptr->prev->_private));
}

void node::prop_name(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    if (!ptr->name)
      data = value();
    else
      data = string((char const *) ptr->name);
    break;
  case property_set:
    xmlNodeSetName(ptr, (xmlChar const *) data.to_string().c_str());
    break;
  default: break;
  };
}

void node::prop_lang(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    {
      xmlChar const *lang = xmlNodeGetLang(ptr);
      if (!lang)
        data = value();
      else
        data = string((char const *) lang);
    }
    break;
  case property_set:
    xmlNodeSetLang(ptr, (xmlChar const *) data.to_string().c_str());
    break;
  default: break;
  };
}

void node::prop_parent(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    if (!ptr->parent)
      data = object();
    else
      data = create(ptr->parent);
    break;
  case property_set:
    if (data.is_void() || data.is_null()) {
      xmlUnlinkNode(ptr);
      data = object();
    } else if (!data.is_object()) {
      data = value();
    } else {
      xmlNodePtr parent = c_from_js(data.get_object());
      if (!parent) {
        data = value();
        break;
      }
      if (ptr->parent)
        xmlUnlinkNode(ptr);
      xmlAddChild(parent, ptr);
    }
    break;
  default: break;
  }
}

void node::prop_next(property_mode mode, value &data) {
  switch (mode) {
  case property_get:
    if (!ptr->parent)
      data = object();
    else
      data = create(ptr->next);
    break;
  case property_set:
    if (data.is_void() || data.is_null()) {
      ptr->next = 0;
      data = object();
    } else if (!data.is_object()) {
      data = value();
    } else {
      xmlNodePtr next = c_from_js(data.get_object());
      if (!next) {
        data = value();
        break;
      }
      ptr->next = next;
      while (next) {
        next->parent = ptr->parent;
        if (!next->next)
          next->parent->last = next;
        next = next->next;
      }
      xmlSetListDoc(ptr->next, ptr->doc);
    }
    break;
  default: break;
  }
}

void node::prop_document(property_mode mode, value &data) {
  if (mode != property_get)
    return;

  if (!ptr->doc)
    data = object();
  else
    data = create(xmlNodePtr(ptr->doc));
}

void node::prop_type(property_mode mode, value &data) {
  if (mode != property_get)
    return;

  switch (ptr->type) {
  case XML_ELEMENT_NODE:
    data = string("ELEMENT");
    break;
  case XML_ATTRIBUTE_NODE:
    data = string("ATTRIBUTE");
    break;
  case XML_TEXT_NODE:
    data = string("TEXT");
    break;
  case XML_CDATA_SECTION_NODE:
    data = string("CDATA-SECTION");
    break;
  case XML_ENTITY_REF_NODE:
    data = string("ENTITY-REFERENCE");
    break;
  case XML_ENTITY_NODE:
    data = string("ENTITY");
    break;
  case XML_PI_NODE:
    data = string("PI");
    break;
  case XML_COMMENT_NODE:
    data = string("COMMENT");
    break;
  case XML_DOCUMENT_NODE:
    data = string("DOCUMENT");
    break;
  case XML_DOCUMENT_TYPE_NODE:
    data = string("DOCUMENT-TYPE");
    break;
  case XML_DOCUMENT_FRAG_NODE:
    data = string("DOCUMENT-FRAGMENT");
    break;
  case XML_NOTATION_NODE:
    data = string("NOTATION");
    break;
  case XML_HTML_DOCUMENT_NODE:
    data = string("HTML-DOCUMENT");
    break;
  case XML_DTD_NODE:
    data = string("DTD");
    break;
  case XML_ELEMENT_DECL:
    data = string("ELEMENT-DECLARATION");
    break;
  case XML_ATTRIBUTE_DECL:
    data = string("ATTRIBUTE-DECLARATION");
    break;
  case XML_ENTITY_DECL:
    data = string("ENTITY-DECLARATION");
    break;
  case XML_NAMESPACE_DECL:
    data = string("NAMESPACE-DECLARATION");
    break;
  case XML_XINCLUDE_START:
    data = string("XINCLUDE-START");
    break;
  case XML_XINCLUDE_END:
    data = string("XINCLUDE-END");
    break;
  default:
    data = string("OTHER");
    break;
  }
}

object node::copy(bool recursive) {
  xmlNodePtr copy = xmlCopyNode(ptr, recursive);

  if (!copy)
    throw exception("Could not copy XML node");

  return create(copy);
}

<|endoftext|>


<commit_before>#include "arena.h"
#include "image_util.h"
#include "image_writer.h"
#include "logger.h"

#include <fstream>

using namespace wotreplay;

const int element_size = 48;

image_writer_t::image_writer_t()
    : filter([](const packet_t &){ return true; }),
      image_width(512), image_height(512)
{}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, int x, int y, int mask) {
    const size_t *shape = element.shape();
    const size_t *image_size = base.shape();
    for (int i = 0; i < shape[0]; ++i) {
        for (int j = 0; j < shape[1]; ++j) {
            // don't touch alpha channel, use from original
            for (int k = 0; k < 3; ++k) {
                if (((i + y) >= image_size[0]) || ((j + x) >= image_size[1])) {
                    continue;
                }
                base[i + y][j + x][k] = mix(base[i + y][j + x][k], base[i + y][j + x][k], (255 - element[i][j][3]) / 255.f,
                                    element[i][j][k] & ((mask >> ((4- (k + 1))*8)) & 0xFF), element[i][j][3] / 255.f);
            }
        }
    }
}

boost::multi_array<uint8_t, 3> image_writer_t::get_element(const std::string &name) {
    boost::multi_array<uint8_t, 3> element, resized_element;
    std::ifstream is("elements/" + name + ".png", std::ios::binary);
    read_png(is, element);
    double f = image_width / 512.0; // we need to scale the elements to the right size
    resize(element, element_size*f, element_size*f, resized_element);
    return resized_element;
}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, std::tuple<float, float> position, int mask) {
    auto shape = base.shape();
    auto element_shape = element.shape();
    float x,y;
    auto position3d = std::make_tuple(std::get<0>(position), 0.f, std::get<1>(position));
    std::tie(x,y) = get_2d_coord(position3d, arena.bounding_box, (int) shape[1], (int) shape[0]);
    draw_element(element, x - element_shape[1]/2, y - element_shape[0]/2, mask);
}

void image_writer_t::draw_grid(boost::multi_array<uint8_t, 3> &image) {
    const int grid_line_width = 2;
    const int grid_cells = 10;
    auto shape = image.shape();
    int grid_width = ((int) shape[1] - (grid_cells + 1) * grid_line_width) / grid_cells;
    int grid_height = ((int) shape[0] - (grid_cells + 1) * grid_line_width) / grid_cells;
    for (int y = 0; y < shape[0]; y += (grid_height + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int x = 0; x < shape[1]; ++x) {
                for (int c = 0; c < 3; ++ c) {
                    image[y + i][x][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
    for (int x = 0; x < shape[1]; x += (grid_width + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int y = 0; y < shape[0]; ++y) {
                for (int c = 0; c < 3; ++ c) {
                    image[y][x + i][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
}

void image_writer_t::draw_elements() {
    auto it = arena.configurations.find(game_mode);
    if (it == arena.configurations.end()) {
        wotreplay::logger.writef(log_level_t::warning, "Could not find configuration for game mode '%1%'\n", game_mode);
        return;
    }

    const arena_configuration_t &configuration = arena.configurations[game_mode];
    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;

    if (game_mode == "domination") {
        auto neutral_base = get_element("neutral_base");
        draw_element(neutral_base, configuration.control_point);
    }

    auto friendly_base = get_element("friendly_base");
    auto enemy_base = get_element("enemy_base");
    for(const auto &entry : configuration.team_base_positions) {
        for (const auto &position : entry.second) {
            draw_element((entry.first - 1) == reference_team_id ? friendly_base : enemy_base, position);
        }
    }

    std::vector<boost::multi_array<uint8_t, 3>> spawns{
        get_element("neutral_spawn1"),
        get_element("neutral_spawn2"),
        get_element("neutral_spawn3"),
        get_element("neutral_spawn4")
    };

    for(const auto &entry : configuration.team_spawn_points) {
        for (int i = 0; i < entry.second.size(); ++i) {
            int mask = (reference_team_id == (entry.first - 1)) ? 0x00FF00FF : 0xFF0000FF;
            draw_element(spawns[i], entry.second[i], mask);
        }
    }

    draw_grid(base);
}

void image_writer_t::draw_death(const packet_t &packet, const game_t &game) {
    uint32_t killer, killed;
    std::tie(killed, killer) = packet.tank_destroyed();
    packet_t position_packet;
    bool found = game.find_property(packet.clock(), killed, property_t::position, position_packet);
    if (found) {
        draw_position(position_packet, game, this->deaths);
    }
}

void image_writer_t::draw_position(const packet_t &packet, const game_t &game, boost::multi_array<float, 3> &image) {
    uint32_t player_id = packet.player_id();

    int team_id = game.get_team_id(player_id);
    if (team_id < 0) return;

    auto shape = image.shape();
    int height = static_cast<int>(shape[1]);
    int width = static_cast<int>(shape[2]);

    const bounding_box_t &bounding_box = game.get_arena().bounding_box;
    std::tuple<float, float> position = get_2d_coord( packet.position(), bounding_box, width, height);
    long x = std::lround(std::get<0>(position));
    long y = std::lround(std::get<1>(position));
    if (x >= 0 && y >= 0 && x < width && y < height) {
        image[team_id][y][x]++;
        if (player_id == game.get_recorder_id()) {
            image[2][y][x]++;
        }
    }
}

void image_writer_t::update(const game_t &game) {
    recorder_team = game.get_team_id(game.get_recorder_id());

    std::set<int> dead_players;
    for (const packet_t &packet : game.get_packets()) {
        if (!filter(packet)) continue;
        if (packet.has_property(property_t::position)
            && dead_players.find(packet.player_id()) == dead_players.end()) {
            draw_position(packet, game, this->positions);
        } else if (packet.has_property(property_t::tank_destroyed)) {
            uint32_t target, killer;
            std::tie(target, killer) = packet.tank_destroyed();
            dead_players.insert(target);
            draw_death(packet, game);
        }
    }
}

void image_writer_t::load_base_map(const std::string &path) {
    boost::multi_array<uint8_t, 3> map;
    std::ifstream is(path, std::ios::binary);
    read_png(is, map);
    resize(map, image_width, image_height, this->base);
}

void image_writer_t::write(std::ostream &os) {
    write_png(os, result);
}

void image_writer_t::init(const arena_t &arena, const std::string &mode) {
    this->arena = arena;
    this->game_mode = mode;

    positions.resize(boost::extents[3][image_height][image_width]);
    deaths.resize(boost::extents[3][image_height][image_width]);

    clear();

    initialized = true;
}

void image_writer_t::clear() {
    std::fill(result.origin(), result.origin() + result.num_elements(), 0.f);
    std::fill(deaths.origin(), deaths.origin() + deaths.num_elements(), 0.f);
    std::fill(positions.origin(), positions.origin() + positions.num_elements(), 0.f);
}

void image_writer_t::finish() {
    draw_basemap();

    const size_t *shape = base.shape();
    result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
    result = base;

    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;
    for (int i = 0; i < image_height; ++i) {
        for (int j = 0; j < image_width; ++j) {
            if (positions[0][i][j] > positions[1][i][j]) {
                // position claimed by first team
                if (reference_team_id == 0) {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                } else {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                }

            } else if (positions[0][i][j] < positions[1][i][j]) {
                // position claimed by second team
                if (reference_team_id == 0) {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                } else {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                }
            } else {
                // no change
            }

            if (this->show_self && positions[2][i][j] > 0.f) {
                // position claimed by second team
                result[i][j][0] = result[i][j][1] = 0x00;
                result[i][j][2] = result[i][j][3] = 0xFF;
            }

            if (deaths[0][i][j] + deaths[1][i][j] > 0.f) {
				for (int k = 0; k < 3; k += 1) {
					for (int l = 0; l < 3; l += 1) {
						int x = j + k - 1;
						int y = i + l - 1;

						// draw only if within bounds
						if (x >= 0 && x < image_width && y >= 0 && y < image_height) {
							result[y][x][3] = result[y][x][0] = result[y][x][1] = 0xFF;
							result[y][x][2] = 0x00;
						}
					}
				}
            }
        }
    }
}

void image_writer_t::reset() {
    // initialize with empty image arrays
    initialized = false;
}

bool image_writer_t::is_initialized() const {
    return initialized;
}

void image_writer_t::set_show_self(bool show_self) {
    this->show_self = show_self;
}

bool image_writer_t::get_show_self() const {
    return show_self;
}

void image_writer_t::set_use_fixed_teamcolors(bool use_fixed_teamcolors) {
    this->use_fixed_teamcolors = use_fixed_teamcolors;
}

bool image_writer_t::get_use_fixed_teamcolors() const {
    return use_fixed_teamcolors;
}

void image_writer_t::set_recorder_team(int recorder_team) {
    this->recorder_team = recorder_team;
}

int image_writer_t::get_recorder_team() const {
    return recorder_team;
}

void image_writer_t::set_filter(filter_t filter) {
    this->filter = filter;
}

const arena_t &image_writer_t::get_arena() const {
    return arena;
}

const std::string &image_writer_t::get_game_mode() const {
    return game_mode;
}

void image_writer_t::merge(const image_writer_t &writer) {
    // TODO: implement this
    std::transform(positions.origin(), positions.origin() + positions.num_elements(),
                   writer.positions.origin(), positions.origin(), std::plus<float>());
}

int image_writer_t::get_image_height() const {
    return image_height;
}

void image_writer_t::set_image_height(int image_height) {
    this->image_height = image_height;
}

int image_writer_t::get_image_width() const {
    return image_width;
}

void image_writer_t::set_image_width(int image_width) {
    this->image_width = image_width;
}

bool image_writer_t::get_no_basemap() const {
    return no_basemap;
}

void image_writer_t::set_no_basemap(bool no_basemap) {
    this->no_basemap = no_basemap;
}

void image_writer_t::draw_basemap() {
    if (!no_basemap) {
        load_base_map(arena.mini_map);
        const size_t *shape = base.shape();
        result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
        draw_elements();
    } else {
        base.resize(boost::extents[image_width][image_height][4]);
    }
}

const boost::multi_array<uint8_t, 3> &image_writer_t::get_result() const {
	return result;
}<commit_msg>image_writer_t::load_base_map() handle failure to open file<commit_after>#include "arena.h"
#include "image_util.h"
#include "image_writer.h"
#include "logger.h"

#include <fstream>

using namespace wotreplay;

const int element_size = 48;

image_writer_t::image_writer_t()
    : filter([](const packet_t &) { return true; }),
    image_width(512), image_height(512)
{}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, int x, int y, int mask) {
    const size_t *shape = element.shape();
    const size_t *image_size = base.shape();
    for (int i = 0; i < shape[0]; ++i) {
        for (int j = 0; j < shape[1]; ++j) {
            // don't touch alpha channel, use from original
            for (int k = 0; k < 3; ++k) {
                if (((i + y) >= image_size[0]) || ((j + x) >= image_size[1])) {
                    continue;
                }
                base[i + y][j + x][k] = mix(base[i + y][j + x][k], base[i + y][j + x][k], (255 - element[i][j][3]) / 255.f,
                    element[i][j][k] & ((mask >> ((4 - (k + 1)) * 8)) & 0xFF), element[i][j][3] / 255.f);
            }
        }
    }
}

boost::multi_array<uint8_t, 3> image_writer_t::get_element(const std::string &name) {
    boost::multi_array<uint8_t, 3> element, resized_element;
    std::ifstream is("elements/" + name + ".png", std::ios::binary);
    read_png(is, element);
    double f = image_width / 512.0; // we need to scale the elements to the right size
    resize(element, element_size*f, element_size*f, resized_element);
    return resized_element;
}

void image_writer_t::draw_element(const boost::multi_array<uint8_t, 3> &element, std::tuple<float, float> position, int mask) {
    auto shape = base.shape();
    auto element_shape = element.shape();
    float x, y;
    auto position3d = std::make_tuple(std::get<0>(position), 0.f, std::get<1>(position));
    std::tie(x, y) = get_2d_coord(position3d, arena.bounding_box, (int) shape[1], (int) shape[0]);
    draw_element(element, x - element_shape[1] / 2, y - element_shape[0] / 2, mask);
}

void image_writer_t::draw_grid(boost::multi_array<uint8_t, 3> &image) {
    const int grid_line_width = 2;
    const int grid_cells = 10;
    auto shape = image.shape();
    int grid_width = ((int) shape[1] - (grid_cells + 1) * grid_line_width) / grid_cells;
    int grid_height = ((int) shape[0] - (grid_cells + 1) * grid_line_width) / grid_cells;
    for (int y = 0; y < shape[0]; y += (grid_height + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int x = 0; x < shape[1]; ++x) {
                for (int c = 0; c < 3; ++c) {
                    image[y + i][x][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
    for (int x = 0; x < shape[1]; x += (grid_width + grid_line_width)) {
        for (int i = 0; i < grid_line_width; ++i) {
            for (int y = 0; y < shape[0]; ++y) {
                for (int c = 0; c < 3; ++c) {
                    image[y][x + i][c] = std::min(image[y][x][c] + 20, 255);
                }
            }
        }
    }
}

void image_writer_t::draw_elements() {
    auto it = arena.configurations.find(game_mode);
    if (it == arena.configurations.end()) {
        wotreplay::logger.writef(log_level_t::warning, "Could not find configuration for game mode '%1%'\n", game_mode);
        return;
    }

    const arena_configuration_t &configuration = arena.configurations[game_mode];
    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;

    if (game_mode == "domination") {
        auto neutral_base = get_element("neutral_base");
        draw_element(neutral_base, configuration.control_point);
    }

    auto friendly_base = get_element("friendly_base");
    auto enemy_base = get_element("enemy_base");
    for (const auto &entry : configuration.team_base_positions) {
        for (const auto &position : entry.second) {
            draw_element((entry.first - 1) == reference_team_id ? friendly_base : enemy_base, position);
        }
    }

    std::vector<boost::multi_array<uint8_t, 3>> spawns{
        get_element("neutral_spawn1"),
        get_element("neutral_spawn2"),
        get_element("neutral_spawn3"),
        get_element("neutral_spawn4")
    };

    for (const auto &entry : configuration.team_spawn_points) {
        for (int i = 0; i < entry.second.size(); ++i) {
            int mask = (reference_team_id == (entry.first - 1)) ? 0x00FF00FF : 0xFF0000FF;
            draw_element(spawns[i], entry.second[i], mask);
        }
    }

    draw_grid(base);
}

void image_writer_t::draw_death(const packet_t &packet, const game_t &game) {
    uint32_t killer, killed;
    std::tie(killed, killer) = packet.tank_destroyed();
    packet_t position_packet;
    bool found = game.find_property(packet.clock(), killed, property_t::position, position_packet);
    if (found) {
        draw_position(position_packet, game, this->deaths);
    }
}

void image_writer_t::draw_position(const packet_t &packet, const game_t &game, boost::multi_array<float, 3> &image) {
    uint32_t player_id = packet.player_id();

    int team_id = game.get_team_id(player_id);
    if (team_id < 0) return;

    auto shape = image.shape();
    int height = static_cast<int>(shape[1]);
    int width = static_cast<int>(shape[2]);

    const bounding_box_t &bounding_box = game.get_arena().bounding_box;
    std::tuple<float, float> position = get_2d_coord(packet.position(), bounding_box, width, height);
    long x = std::lround(std::get<0>(position));
    long y = std::lround(std::get<1>(position));
    if (x >= 0 && y >= 0 && x < width && y < height) {
        image[team_id][y][x]++;
        if (player_id == game.get_recorder_id()) {
            image[2][y][x]++;
        }
    }
}

void image_writer_t::update(const game_t &game) {
    recorder_team = game.get_team_id(game.get_recorder_id());

    std::set<int> dead_players;
    for (const packet_t &packet : game.get_packets()) {
        if (!filter(packet)) continue;
        if (packet.has_property(property_t::position)
            && dead_players.find(packet.player_id()) == dead_players.end()) {
            draw_position(packet, game, this->positions);
        }
        else if (packet.has_property(property_t::tank_destroyed)) {
            uint32_t target, killer;
            std::tie(target, killer) = packet.tank_destroyed();
            dead_players.insert(target);
            draw_death(packet, game);
        }
    }
}

void image_writer_t::load_base_map(const std::string &path) {
    boost::multi_array<uint8_t, 3> map;
    std::ifstream is(path, std::ios::binary);
    if (is) {
        read_png(is, map);
        resize(map, image_width, image_height, this->base);
    }
}

void image_writer_t::write(std::ostream &os) {
    write_png(os, result);
}

void image_writer_t::init(const arena_t &arena, const std::string &mode) {
    this->arena = arena;
    this->game_mode = mode;

    positions.resize(boost::extents[3][image_height][image_width]);
    deaths.resize(boost::extents[3][image_height][image_width]);

    clear();

    initialized = true;
}

void image_writer_t::clear() {
    std::fill(result.origin(), result.origin() + result.num_elements(), 0.f);
    std::fill(deaths.origin(), deaths.origin() + deaths.num_elements(), 0.f);
    std::fill(positions.origin(), positions.origin() + positions.num_elements(), 0.f);
}

void image_writer_t::finish() {
    draw_basemap();

    const size_t *shape = base.shape();
    result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
    result = base;

    int reference_team_id = use_fixed_teamcolors ? 0 : recorder_team;
    for (int i = 0; i < image_height; ++i) {
        for (int j = 0; j < image_width; ++j) {
            if (positions[0][i][j] > positions[1][i][j]) {
                // position claimed by first team
                if (reference_team_id == 0) {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                }
                else {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                }

            }
            else if (positions[0][i][j] < positions[1][i][j]) {
                // position claimed by second team
                if (reference_team_id == 0) {
                    result[i][j][1] = result[i][j][2] = 0x00;
                    result[i][j][0] = result[i][j][3] = 0xFF;
                }
                else {
                    result[i][j][0] = result[i][j][2] = 0x00;
                    result[i][j][1] = result[i][j][3] = 0xFF;
                }
            }
            else {
                // no change
            }

            if (this->show_self && positions[2][i][j] > 0.f) {
                // position claimed by second team
                result[i][j][0] = result[i][j][1] = 0x00;
                result[i][j][2] = result[i][j][3] = 0xFF;
            }

            if (deaths[0][i][j] + deaths[1][i][j] > 0.f) {
                for (int k = 0; k < 3; k += 1) {
                    for (int l = 0; l < 3; l += 1) {
                        int x = j + k - 1;
                        int y = i + l - 1;

                        // draw only if within bounds
                        if (x >= 0 && x < image_width && y >= 0 && y < image_height) {
                            result[y][x][3] = result[y][x][0] = result[y][x][1] = 0xFF;
                            result[y][x][2] = 0x00;
                        }
                    }
                }
            }
        }
    }
}

void image_writer_t::reset() {
    // initialize with empty image arrays
    initialized = false;
}

bool image_writer_t::is_initialized() const {
    return initialized;
}

void image_writer_t::set_show_self(bool show_self) {
    this->show_self = show_self;
}

bool image_writer_t::get_show_self() const {
    return show_self;
}

void image_writer_t::set_use_fixed_teamcolors(bool use_fixed_teamcolors) {
    this->use_fixed_teamcolors = use_fixed_teamcolors;
}

bool image_writer_t::get_use_fixed_teamcolors() const {
    return use_fixed_teamcolors;
}

void image_writer_t::set_recorder_team(int recorder_team) {
    this->recorder_team = recorder_team;
}

int image_writer_t::get_recorder_team() const {
    return recorder_team;
}

void image_writer_t::set_filter(filter_t filter) {
    this->filter = filter;
}

const arena_t &image_writer_t::get_arena() const {
    return arena;
}

const std::string &image_writer_t::get_game_mode() const {
    return game_mode;
}

void image_writer_t::merge(const image_writer_t &writer) {
    // TODO: implement this
    std::transform(positions.origin(), positions.origin() + positions.num_elements(),
        writer.positions.origin(), positions.origin(), std::plus<float>());
}

int image_writer_t::get_image_height() const {
    return image_height;
}

void image_writer_t::set_image_height(int image_height) {
    this->image_height = image_height;
}

int image_writer_t::get_image_width() const {
    return image_width;
}

void image_writer_t::set_image_width(int image_width) {
    this->image_width = image_width;
}

bool image_writer_t::get_no_basemap() const {
    return no_basemap;
}

void image_writer_t::set_no_basemap(bool no_basemap) {
    this->no_basemap = no_basemap;
}

void image_writer_t::draw_basemap() {
    if (!no_basemap) {
        load_base_map(arena.mini_map);
        const size_t *shape = base.shape();
        result.resize(boost::extents[shape[0]][shape[1]][shape[2]]);
        draw_elements();
    }
    else {
        base.resize(boost::extents[image_width][image_height][4]);
    }
}

const boost::multi_array<uint8_t, 3> &image_writer_t::get_result() const {
    return result;
}<|endoftext|>


<commit_before><commit_msg>Added a new optional command-line flag to allow filtering of open-access records.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2014 Wenbin He. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

#include "io/raw_reader.h"

#include "core/basic_types.h"
#include "core/cartesian_grid.h"
#include "core/field.h"
#include "core/float_array.h"
#include "io/console.h"

namespace itl {

std::unique_ptr<Field> RawReader::LoadData(
    std::initializer_list<std::pair<const char*, int>> file_list,
    bool with_header) {
  if (with_header) {
    FILE* file;
    file = fopen(file_list.begin()->first, "rb");
    int dimensions[3];
    fread(dimensions, sizeof(int), 3, file);
    set_dimensions(dimensions[0], dimensions[1], dimensions[2]);
    fclose(file);
  }

  int data_size = x_dim_ * y_dim_ * z_dim_;
  std::unique_ptr<Grid> grid(new CartesianGrid(x_dim_, y_dim_, z_dim_,
                                               x_bias_, y_bias_, z_bias_));

  std::unique_ptr<Field> field(new Field());
  field->set_grid(grid.release());

  for (auto it = file_list.begin(); it != file_list.end(); ++it) {
    FILE* file;
    file = fopen(it->first, "rb");

    if (with_header) {
      int dimensions[3];
      fread(dimensions, sizeof(int), 3, file);
    }

    std::unique_ptr<AbstractArray> array;

    switch (it->second) {
      case kFloat:
        array.reset(new FloatArray(data_size));
        fread(static_cast<FloatArray*>(array.get())->data(),
              sizeof(float), data_size, file);
        break;
      default:
        Console::Warn("RawReader::LoadData() given unsupported data type.");
    }

    fclose(file);
    field->attach_variable(array.release());
  }

  return field;
}

}  // namespace itl
<commit_msg>Update RawReader<commit_after>// Copyright (c) 2014 Wenbin He. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

#include "io/raw_reader.h"

#include "core/basic_types.h"
#include "core/cartesian_grid.h"
#include "core/field.h"
#include "core/float_array.h"
#include "core/double_array.h"
#include "core/int32_array.h"
#include "io/console.h"

namespace itl {

std::unique_ptr<Field> RawReader::LoadData(
    std::initializer_list<std::pair<const char*, int>> file_list,
    bool with_header) {
  if (with_header) {
    FILE* file;
    file = fopen(file_list.begin()->first, "rb");
    int dimensions[3];
    fread(dimensions, sizeof(int), 3, file);
    set_dimensions(dimensions[0], dimensions[1], dimensions[2]);
    fclose(file);
  }

  int data_size = x_dim_ * y_dim_ * z_dim_;
  std::unique_ptr<Grid> grid(new CartesianGrid(x_dim_, y_dim_, z_dim_,
                                               x_bias_, y_bias_, z_bias_));

  std::unique_ptr<Field> field(new Field());
  field->set_grid(grid.release());

  for (auto it = file_list.begin(); it != file_list.end(); ++it) {
    FILE* file;
    file = fopen(it->first, "rb");

    if (with_header) {
      int dimensions[3];
      fread(dimensions, sizeof(int), 3, file);
    }

    std::unique_ptr<AbstractArray> array;

    switch (it->second) {
      case kFloat:
        array.reset(new FloatArray(data_size));
        fread(static_cast<FloatArray*>(array.get())->data(),
              sizeof(float), data_size, file);
        break;
      case kDouble:
        array.reset(new DoubleArray(data_size));
        fread(static_cast<DoubleArray*>(array.get())->data(),
              sizeof(double), data_size, file);
        break;
      case kInt32:
        array.reset(new Int32Array(data_size));
        fread(static_cast<Int32Array*>(array.get())->data(),
              sizeof(int32_t), data_size, file);
      default:
        Console::Warn("RawReader::LoadData() given unsupported data type.");
    }

    fclose(file);
    field->attach_variable(array.release());
  }

  return field;
}

}  // namespace itl
<|endoftext|>


<commit_before>#include "itemrenderer.h"

#include <sstream>

#include "configcontainer.h"
#include "htmlrenderer.h"
#include "rssfeed.h"
#include "textformatter.h"

namespace newsboat {

std::string item_renderer::get_feedtitle(std::shared_ptr<RssItem> item) {
	const std::shared_ptr<RssFeed> feedptr = item->get_feedptr();

	std::string feedtitle;
	if (feedptr) {
		if (!feedptr->title().empty()) {
			feedtitle = feedptr->title();
			utils::remove_soft_hyphens(feedtitle);
		} else if (!feedptr->link().empty()) {
			feedtitle = feedptr->link();
		} else if (!feedptr->rssurl().empty()) {
			feedtitle = feedptr->rssurl();
		}
	}

	return feedtitle;
}

void prepare_header(
	std::shared_ptr<RssItem> item,
	std::vector<std::pair<LineType, std::string>>& lines,
	std::vector<LinkPair>& /*links*/)
{
	const auto add_line =
		[&lines]
		(const std::string& value,
		 const std::string& name,
		 LineType lineType = LineType::wrappable)
		{
			if (!value.empty()) {
				const auto line = strprintf::fmt("%s%s", name, value);
				lines.push_back(std::make_pair(lineType, line));
			}
		};

	const std::string feedtitle = item_renderer::get_feedtitle(item);
	add_line(feedtitle, _("Feed: "));
	add_line(item->title(), _("Title: "));
	add_line(item->author(), _("Author: "));
	add_line(item->pubDate(), _("Date: "));
	add_line(item->link(), _("Link: "), LineType::softwrappable);
	add_line(item->flags(), _("Flags: "));

	if (!item->enclosure_url().empty()) {
		auto dlurl = strprintf::fmt(
			"%s%s",
			_("Podcast Download URL: "),
			utils::censor_url(item->enclosure_url()));
		if (!item->enclosure_type().empty()) {
			dlurl.append(
					strprintf::fmt(" (%s%s)",
						_("type: "),
						item->enclosure_type()));
		}
		lines.push_back(std::make_pair(LineType::softwrappable, dlurl));
	}

	lines.push_back(std::make_pair(LineType::wrappable, std::string("")));
}

std::string get_item_base_link(const std::shared_ptr<RssItem>& item)
{
	if (!item->get_base().empty()) {
		return item->get_base();
	} else {
		return item->feedurl();
	}
}

void render_html(
	ConfigContainer& cfg,
	const std::string& source,
	std::vector<std::pair<LineType, std::string>>& lines,
	std::vector<LinkPair>& thelinks,
	const std::string& url,
	bool raw)
{
	const std::string renderer = cfg.get_configvalue("html-renderer");
	if (renderer == "internal") {
		HtmlRenderer rnd(raw);
		rnd.render(source, lines, thelinks, url);
	} else {
		char* argv[4];
		argv[0] = const_cast<char*>("/bin/sh");
		argv[1] = const_cast<char*>("-c");
		argv[2] = const_cast<char*>(renderer.c_str());
		argv[3] = nullptr;
		LOG(Level::DEBUG,
			"item_renderer::render_html: source = %s",
			source);
		LOG(Level::DEBUG,
			"item_renderer::render_html: html-renderer = %s",
			argv[2]);

		const std::string output = utils::run_program(argv, source);
		std::istringstream is(output);
		std::string line;
		while (!is.eof()) {
			getline(is, line);
			if (!raw) {
				line = utils::quote_for_stfl(line);
			}
			lines.push_back(std::make_pair(LineType::softwrappable, line));
		}
	}
}

std::string item_renderer::to_plain_text(
		ConfigContainer& cfg,
		std::shared_ptr<RssItem> item)
{
	std::vector<std::pair<LineType, std::string>> lines;
	std::vector<LinkPair> links;

	prepare_header(item, lines, links);
	const auto base = get_item_base_link(item);
	render_html(cfg, item->description(), lines, links, base, true);

	TextFormatter txtfmt;
	txtfmt.add_lines(lines);

	unsigned int width = cfg.get_configvalue_as_int("text-width");
	if (width == 0) {
		width = 80;
	}

	return txtfmt.format_text_plain(width);
}

std::pair<std::string, size_t> item_renderer::to_stfl_list(
		ConfigContainer& cfg,
		std::shared_ptr<RssItem> item,
		unsigned int text_width,
		unsigned int window_width,
		RegexManager* rxman,
		const std::string& location,
		std::vector<LinkPair>& links)
{
	std::vector<std::pair<LineType, std::string>> lines;

	prepare_header(item, lines, links);
	const std::string baseurl = get_item_base_link(item);
	const auto body = item->description();
	render_html(cfg, body, lines, links, baseurl, false);

	TextFormatter txtfmt;
	txtfmt.add_lines(lines);

	return txtfmt.format_text_to_list(rxman, location, text_width, window_width);
}

void render_source(
	std::vector<std::pair<LineType, std::string>>& lines,
	std::string source)
{
	/*
	 * This function is called instead of HtmlRenderer::render() when the
	 * user requests to have the source displayed instead of seeing the
	 * rendered HTML.
	 */
	std::string line;
	do {
		std::string::size_type pos = source.find_first_of("\r\n");
		line = source.substr(0, pos);
		if (pos == std::string::npos) {
			source.erase();
		} else {
			source.erase(0, pos + 1);
		}
		lines.push_back(std::make_pair(LineType::softwrappable, line));
	} while (source.length() > 0);
}

std::pair<std::string, size_t> item_renderer::source_to_stfl_list(
		std::shared_ptr<RssItem> item,
		unsigned int text_width,
		unsigned int window_width,
		RegexManager* rxman,
		const std::string& location)
{
	std::vector<std::pair<LineType, std::string>> lines;
	std::vector<LinkPair> links;

	prepare_header(item, lines, links);
	render_source(lines, utils::quote_for_stfl(item->description()));

	TextFormatter txtfmt;
	txtfmt.add_lines(lines);

	return txtfmt.format_text_to_list(rxman, location, text_width, window_width);
}

}
<commit_msg>Minimize nesting in item_renderer::get_feedtitle<commit_after>#include "itemrenderer.h"

#include <sstream>

#include "configcontainer.h"
#include "htmlrenderer.h"
#include "rssfeed.h"
#include "textformatter.h"

namespace newsboat {

std::string item_renderer::get_feedtitle(std::shared_ptr<RssItem> item) {
	const std::shared_ptr<RssFeed> feedptr = item->get_feedptr();

	if (!feedptr) {
		return {};
	}

	std::string feedtitle;
	if (!feedptr->title().empty()) {
		feedtitle = feedptr->title();
		utils::remove_soft_hyphens(feedtitle);
	} else if (!feedptr->link().empty()) {
		feedtitle = feedptr->link();
	} else if (!feedptr->rssurl().empty()) {
		feedtitle = feedptr->rssurl();
	}

	return feedtitle;
}

void prepare_header(
	std::shared_ptr<RssItem> item,
	std::vector<std::pair<LineType, std::string>>& lines,
	std::vector<LinkPair>& /*links*/)
{
	const auto add_line =
		[&lines]
		(const std::string& value,
		 const std::string& name,
		 LineType lineType = LineType::wrappable)
		{
			if (!value.empty()) {
				const auto line = strprintf::fmt("%s%s", name, value);
				lines.push_back(std::make_pair(lineType, line));
			}
		};

	const std::string feedtitle = item_renderer::get_feedtitle(item);
	add_line(feedtitle, _("Feed: "));
	add_line(item->title(), _("Title: "));
	add_line(item->author(), _("Author: "));
	add_line(item->pubDate(), _("Date: "));
	add_line(item->link(), _("Link: "), LineType::softwrappable);
	add_line(item->flags(), _("Flags: "));

	if (!item->enclosure_url().empty()) {
		auto dlurl = strprintf::fmt(
			"%s%s",
			_("Podcast Download URL: "),
			utils::censor_url(item->enclosure_url()));
		if (!item->enclosure_type().empty()) {
			dlurl.append(
					strprintf::fmt(" (%s%s)",
						_("type: "),
						item->enclosure_type()));
		}
		lines.push_back(std::make_pair(LineType::softwrappable, dlurl));
	}

	lines.push_back(std::make_pair(LineType::wrappable, std::string("")));
}

std::string get_item_base_link(const std::shared_ptr<RssItem>& item)
{
	if (!item->get_base().empty()) {
		return item->get_base();
	} else {
		return item->feedurl();
	}
}

void render_html(
	ConfigContainer& cfg,
	const std::string& source,
	std::vector<std::pair<LineType, std::string>>& lines,
	std::vector<LinkPair>& thelinks,
	const std::string& url,
	bool raw)
{
	const std::string renderer = cfg.get_configvalue("html-renderer");
	if (renderer == "internal") {
		HtmlRenderer rnd(raw);
		rnd.render(source, lines, thelinks, url);
	} else {
		char* argv[4];
		argv[0] = const_cast<char*>("/bin/sh");
		argv[1] = const_cast<char*>("-c");
		argv[2] = const_cast<char*>(renderer.c_str());
		argv[3] = nullptr;
		LOG(Level::DEBUG,
			"item_renderer::render_html: source = %s",
			source);
		LOG(Level::DEBUG,
			"item_renderer::render_html: html-renderer = %s",
			argv[2]);

		const std::string output = utils::run_program(argv, source);
		std::istringstream is(output);
		std::string line;
		while (!is.eof()) {
			getline(is, line);
			if (!raw) {
				line = utils::quote_for_stfl(line);
			}
			lines.push_back(std::make_pair(LineType::softwrappable, line));
		}
	}
}

std::string item_renderer::to_plain_text(
		ConfigContainer& cfg,
		std::shared_ptr<RssItem> item)
{
	std::vector<std::pair<LineType, std::string>> lines;
	std::vector<LinkPair> links;

	prepare_header(item, lines, links);
	const auto base = get_item_base_link(item);
	render_html(cfg, item->description(), lines, links, base, true);

	TextFormatter txtfmt;
	txtfmt.add_lines(lines);

	unsigned int width = cfg.get_configvalue_as_int("text-width");
	if (width == 0) {
		width = 80;
	}

	return txtfmt.format_text_plain(width);
}

std::pair<std::string, size_t> item_renderer::to_stfl_list(
		ConfigContainer& cfg,
		std::shared_ptr<RssItem> item,
		unsigned int text_width,
		unsigned int window_width,
		RegexManager* rxman,
		const std::string& location,
		std::vector<LinkPair>& links)
{
	std::vector<std::pair<LineType, std::string>> lines;

	prepare_header(item, lines, links);
	const std::string baseurl = get_item_base_link(item);
	const auto body = item->description();
	render_html(cfg, body, lines, links, baseurl, false);

	TextFormatter txtfmt;
	txtfmt.add_lines(lines);

	return txtfmt.format_text_to_list(rxman, location, text_width, window_width);
}

void render_source(
	std::vector<std::pair<LineType, std::string>>& lines,
	std::string source)
{
	/*
	 * This function is called instead of HtmlRenderer::render() when the
	 * user requests to have the source displayed instead of seeing the
	 * rendered HTML.
	 */
	std::string line;
	do {
		std::string::size_type pos = source.find_first_of("\r\n");
		line = source.substr(0, pos);
		if (pos == std::string::npos) {
			source.erase();
		} else {
			source.erase(0, pos + 1);
		}
		lines.push_back(std::make_pair(LineType::softwrappable, line));
	} while (source.length() > 0);
}

std::pair<std::string, size_t> item_renderer::source_to_stfl_list(
		std::shared_ptr<RssItem> item,
		unsigned int text_width,
		unsigned int window_width,
		RegexManager* rxman,
		const std::string& location)
{
	std::vector<std::pair<LineType, std::string>> lines;
	std::vector<LinkPair> links;

	prepare_header(item, lines, links);
	render_source(lines, utils::quote_for_stfl(item->description()));

	TextFormatter txtfmt;
	txtfmt.add_lines(lines);

	return txtfmt.format_text_to_list(rxman, location, text_width, window_width);
}

}
<|endoftext|>