text:
#ifndef BOOST_PP_IS_ITERATING
    ///////////////////////////////////////////////////////////////////////////////
    /// \file default.hpp
    /// Contains definition of the _default transform, which gives operators their
    /// usual C++ meanings and uses Boost.Typeof to deduce return types.
    //
    //  Copyright 2008 Eric Niebler. Distributed under the Boost
    //  Software License, Version 1.0. (See accompanying file
    //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

    #ifndef BOOST_PROTO_TRANSFORM_DEFAULT_HPP_EAN_04_04_2008
    #define BOOST_PROTO_TRANSFORM_DEFAULT_HPP_EAN_04_04_2008

    #include <boost/proto/detail/prefix.hpp>
    #include <boost/preprocessor/iteration/iterate.hpp>
    #include <boost/preprocessor/repetition/repeat.hpp>
    #include <boost/preprocessor/repetition/enum_shifted.hpp>
    #include <boost/preprocessor/repetition/enum_shifted_params.hpp>
    #include <boost/ref.hpp>
    #include <boost/get_pointer.hpp>
    #include <boost/utility/enable_if.hpp>
    #include <boost/type_traits/is_member_pointer.hpp>
    #include <boost/type_traits/is_member_object_pointer.hpp>
    #include <boost/type_traits/is_member_function_pointer.hpp>
    #include <boost/proto/proto_fwd.hpp>
    #include <boost/proto/traits.hpp>
    #include <boost/proto/transform/impl.hpp>
    #include <boost/proto/transform/arg.hpp>
    #include <boost/proto/detail/decltype.hpp>
    #include <boost/proto/detail/suffix.hpp>

    namespace boost { namespace proto
    {
        template<typename Grammar BOOST_PROTO_WHEN_BUILDING_DOCS(= detail::_default)>
        struct _default
          : transform<_default<Grammar> >
        {
            template<typename Expr, typename State, typename Data, typename Tag, long Arity>
            struct impl2;

            template<typename Expr, typename State, typename Data, typename Tag>
            struct impl2<Expr, State, Data, Tag, 0>
              : _value::impl<Expr, State, Data>
            {};

            #define BOOST_PROTO_UNARY_OP_RESULT(OP, TAG, MAKE)                                      \
            template<typename Expr, typename State, typename Data>                                  \
            struct impl2<Expr, State, Data, TAG, 1>                                                 \
              : transform_impl<Expr, State, Data>                                                   \
            {                                                                                \
            private:                                                                                \
                typedef typename result_of::child_c<Expr, 0>::type e0;                              \
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;           \
            public:                                                                                \
                BOOST_PROTO_DECLTYPE_(OP proto::detail::MAKE<r0>(), result_type)                    \
                result_type operator ()(                                                            \
                    typename impl2::expr_param e                                                    \
                  , typename impl2::state_param s                                                   \
                  , typename impl2::data_param d                                                    \
                ) const                                                                             \
                {                                                                                \
                    typename Grammar::template impl<e0, State, Data> t0;                            \
                    return OP t0(proto::child_c<0>(e), s, d);                                       \
                }                                                                                \
            };                                                                                \
            /**/

            #define BOOST_PROTO_BINARY_OP_RESULT(OP, TAG, LMAKE, RMAKE)                             \
            template<typename Expr, typename State, typename Data>                                  \
            struct impl2<Expr, State, Data, TAG, 2>                                                 \
              : transform_impl<Expr, State, Data>                                                   \
            {                                                                                \
            private:                                                                                \
                typedef typename result_of::child_c<Expr, 0>::type e0;                              \
                typedef typename result_of::child_c<Expr, 1>::type e1;                              \
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;           \
                typedef typename Grammar::template impl<e1, State, Data>::result_type r1;           \
            public:                                                                                \
                BOOST_PROTO_DECLTYPE_(                                                              \
                    proto::detail::LMAKE<r0>() OP proto::detail::RMAKE<r1>()                        \
                  , result_type                                                                     \
                )                                                                                \
                result_type operator ()(                                                            \
                    typename impl2::expr_param e                                                    \
                  , typename impl2::state_param s                                                   \
                  , typename impl2::data_param d                                                    \
                ) const                                                                             \
                {                                                                                \
                    typename Grammar::template impl<e0, State, Data> t0;                            \
                    typename Grammar::template impl<e1, State, Data> t1;                            \
                    return t0(proto::child_c<0>(e), s, d)                                           \
                        OP t1(proto::child_c<1>(e), s, d);                                          \
                }                                                                                \
            };                                                                                \
            /**/

            BOOST_PROTO_UNARY_OP_RESULT(+, tag::unary_plus, make)
            BOOST_PROTO_UNARY_OP_RESULT(-, tag::negate, make)
            BOOST_PROTO_UNARY_OP_RESULT(*, tag::dereference, make)
            BOOST_PROTO_UNARY_OP_RESULT(~, tag::complement, make)
            BOOST_PROTO_UNARY_OP_RESULT(&, tag::address_of, make)
            BOOST_PROTO_UNARY_OP_RESULT(!, tag::logical_not, make)
            BOOST_PROTO_UNARY_OP_RESULT(++, tag::pre_inc, make_mutable)
            BOOST_PROTO_UNARY_OP_RESULT(--, tag::pre_dec, make_mutable)

            BOOST_PROTO_BINARY_OP_RESULT(<<, tag::shift_left, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(>>, tag::shift_right, make_mutable, make_mutable)
            BOOST_PROTO_BINARY_OP_RESULT(*, tag::multiplies, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(/, tag::divides, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(%, tag::modulus, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(+, tag::plus, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(-, tag::minus, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(<, tag::less, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(>, tag::greater, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(<=, tag::less_equal, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(>=, tag::greater_equal, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(==, tag::equal_to, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(!=, tag::not_equal_to, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(||, tag::logical_or, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(&&, tag::logical_and, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(&, tag::bitwise_and, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(|, tag::bitwise_or, make, make)
            BOOST_PROTO_BINARY_OP_RESULT(^, tag::bitwise_xor, make, make)

            BOOST_PROTO_BINARY_OP_RESULT(=, tag::assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(<<=, tag::shift_left_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(>>=, tag::shift_right_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(*=, tag::multiplies_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(/=, tag::divides_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(%=, tag::modulus_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(+=, tag::plus_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(-=, tag::minus_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(&=, tag::bitwise_and_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(|=, tag::bitwise_or_assign, make_mutable, make)
            BOOST_PROTO_BINARY_OP_RESULT(^=, tag::bitwise_xor_assign, make_mutable, make)

            #undef BOOST_PROTO_UNARY_OP_RESULT
            #undef BOOST_PROTO_BINARY_OP_RESULT

            /// INTERNAL ONLY
            template<typename Expr, typename State, typename Data>
            struct is_member_function_invocation
              : is_member_function_pointer<
                    typename remove_const<
                        typename remove_reference<
                            typename Grammar::template impl<
                                typename result_of::child_c<Expr, 1>::type
                              , State
                              , Data
                            >::result_type
                        >::type
                    >::type
                >
            {};

            /// INTERNAL ONLY
            template<typename Expr, typename State, typename Data, bool IsMemFunCall>
            struct memfun_impl
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename result_of::child_c<Expr, 1>::type e1;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
                typedef typename Grammar::template impl<e1, State, Data>::result_type r1;
            public:
                typedef typename detail::mem_ptr_fun<r0, r1>::result_type result_type;
                result_type operator ()(
                    typename memfun_impl::expr_param e
                  , typename memfun_impl::state_param s
                  , typename memfun_impl::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    typename Grammar::template impl<e1, State, Data> t1;
                    return detail::mem_ptr_fun<r0, r1>()(
                        t0(proto::child_c<0>(e), s, d)
                      , t1(proto::child_c<1>(e), s, d)
                    );
                }
            };

            /// INTERNAL ONLY
            template<typename Expr, typename State, typename Data>
            struct memfun_impl<Expr, State, Data, true>
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename result_of::child_c<Expr, 1>::type e1;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
                typedef typename Grammar::template impl<e1, State, Data>::result_type r1;
            public:
                typedef detail::memfun<r0, r1> result_type;
                result_type const operator ()(
                    typename memfun_impl::expr_param e
                  , typename memfun_impl::state_param s
                  , typename memfun_impl::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    typename Grammar::template impl<e1, State, Data> t1;
                    return detail::memfun<r0, r1>(
                        t0(proto::child_c<0>(e), s, d)
                      , t1(proto::child_c<1>(e), s, d)
                    );
                }
            };

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::mem_ptr, 2>
              : memfun_impl<Expr, State, Data, is_member_function_invocation<Expr, State, Data>::value>
            {};

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::post_inc, 1>
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
            public:
                BOOST_PROTO_DECLTYPE_(proto::detail::make_mutable<r0>() ++, result_type)
                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    return t0(proto::child_c<0>(e), s, d) ++;
                }
            };

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::post_dec, 1>
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
            public:
                BOOST_PROTO_DECLTYPE_(proto::detail::make_mutable<r0>() --, result_type)
                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    return t0(proto::child_c<0>(e), s, d) --;
                }
            };

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::subscript, 2>
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename result_of::child_c<Expr, 1>::type e1;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
                typedef typename Grammar::template impl<e1, State, Data>::result_type r1;
            public:
                BOOST_PROTO_DECLTYPE_(
                    proto::detail::make_subscriptable<r0>() [ proto::detail::make<r1>() ]
                  , result_type
                )
                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    typename Grammar::template impl<e1, State, Data> t1;
                    return t0(proto::child_c<0>(e), s, d) [
                           t1(proto::child_c<1>(e), s, d) ];
                }
            };

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::if_else_, 3>
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename result_of::child_c<Expr, 1>::type e1;
                typedef typename result_of::child_c<Expr, 2>::type e2;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
                typedef typename Grammar::template impl<e1, State, Data>::result_type r1;
                typedef typename Grammar::template impl<e2, State, Data>::result_type r2;
            public:
                BOOST_PROTO_DECLTYPE_(
                    proto::detail::make<r0>()
                  ? proto::detail::make<r1>()
                  : proto::detail::make<r2>()
                  , result_type
                )
                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    typename Grammar::template impl<e1, State, Data> t1;
                    typename Grammar::template impl<e2, State, Data> t2;
                    return t0(proto::child_c<0>(e), s, d)
                         ? t1(proto::child_c<1>(e), s, d)
                         : t2(proto::child_c<2>(e), s, d);
                }
            };

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::comma, 2>
              : transform_impl<Expr, State, Data>
            {
            private:
                typedef typename result_of::child_c<Expr, 0>::type e0;
                typedef typename result_of::child_c<Expr, 1>::type e1;
                typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
                typedef typename Grammar::template impl<e1, State, Data>::result_type r1;
            public:
                typedef typename proto::detail::comma_result<r0, r1>::type result_type;
                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    typename Grammar::template impl<e0, State, Data> t0;
                    typename Grammar::template impl<e1, State, Data> t1;
                    return t0(proto::child_c<0>(e), s, d)
                         , t1(proto::child_c<1>(e), s, d);
                }
            };

            #define EVAL_TYPE(Z, N, DATA)                                                           \
                typedef                                                                             \
                    typename result_of::child_c<DATA, N>::type                                      \
                BOOST_PP_CAT(e, N);                                                                 \
                typedef                                                                             \
                    typename Grammar::template impl<BOOST_PP_CAT(e, N), State, Data>::result_type   \
                BOOST_PP_CAT(r, N);                                                                 \
                /**/

            #define EVAL(Z, N, DATA)                                                                \
                typename Grammar::template impl<BOOST_PP_CAT(e, N), State, Data>()(                 \
                    proto::child_c<N>(DATA), s, d                                            \
                )                                                                                \
                /**/

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::function, 1>
              : transform_impl<Expr, State, Data>
            {
                EVAL_TYPE(~, 0, Expr)

                typedef
                    typename proto::detail::result_of_fixup<r0>::type
                function_type;

                typedef
                    typename boost::result_of<function_type()>::type
                result_type;

                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    return EVAL(~, 0, e)();
                }
            };

            template<typename Expr, typename State, typename Data>
            struct impl2<Expr, State, Data, tag::function, 2>
              : transform_impl<Expr, State, Data>
            {
                EVAL_TYPE(~, 0, Expr)
                EVAL_TYPE(~, 1, Expr)

                typedef
                    typename proto::detail::result_of_fixup<r0>::type
                function_type;

                typedef
                    typename detail::result_of_<function_type(r1)>::type
                result_type;

                result_type operator ()(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                ) const
                {
                    return this->invoke(
                        e
                      , s
                      , d
                      , is_member_function_pointer<function_type>()
                      , is_member_object_pointer<function_type>()
                    );
                }

            private:
                result_type invoke(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                  , mpl::false_
                  , mpl::false_
                ) const
                {
                    return EVAL(~, 0, e)(EVAL(~, 1, e));
                }

                result_type invoke(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                  , mpl::true_
                  , mpl::false_
                ) const
                {
                    BOOST_PROTO_USE_GET_POINTER();
                    typedef typename detail::classtypeof<function_type>::type class_type;
                    return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, e)) ->* EVAL(~, 0, e))();
                }

                result_type invoke(
                    typename impl2::expr_param e
                  , typename impl2::state_param s
                  , typename impl2::data_param d
                  , mpl::false_
                  , mpl::true_
                ) const
                {
                    BOOST_PROTO_USE_GET_POINTER();
                    typedef typename detail::classtypeof<function_type>::type class_type;
                    return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, e)) ->* EVAL(~, 0, e));
                }
            };

            #define BOOST_PP_ITERATION_PARAMS_1 (3, (3, BOOST_PROTO_MAX_ARITY, <boost/proto/transform/default.hpp>))
            #include BOOST_PP_ITERATE()

            #undef EVAL_TYPE
            #undef EVAL

            template<typename Expr, typename State, typename Data>
            struct impl
              : impl2<
                    Expr
                  , State
                  , Data
                  , typename transform_impl<Expr, State, Data>::expr::proto_tag
                  , transform_impl<Expr, State, Data>::expr::proto_arity_c
                >
            {};
        };

        template<typename Grammar>
        struct is_callable<_default<Grammar> >
          : mpl::true_
        {};

        namespace detail
        {
            // Loopy indirection that allows proto::_default<> to be
            // used without specifying a Grammar argument.
            struct _default
              : proto::_default<>
            {};
        }

    }}

    #endif

#else

    #define N BOOST_PP_ITERATION()

        template<typename Expr, typename State, typename Data>
        struct impl2<Expr, State, Data, tag::function, N>
          : transform_impl<Expr, State, Data>
        {
            BOOST_PP_REPEAT(N, EVAL_TYPE, Expr)

            typedef
                typename proto::detail::result_of_fixup<r0>::type
            function_type;

            typedef
                typename boost::result_of<
                    function_type(BOOST_PP_ENUM_SHIFTED_PARAMS(N, r))
                >::type
            result_type;

            result_type operator ()(
                typename impl2::expr_param e
              , typename impl2::state_param s
              , typename impl2::data_param d
            ) const
            {
                return this->invoke(e, s, d, is_member_function_pointer<function_type>());
            }

        private:
            result_type invoke(
                typename impl2::expr_param e
              , typename impl2::state_param s
              , typename impl2::data_param d
              , mpl::false_
            ) const
            {
                return EVAL(~, 0, e)(BOOST_PP_ENUM_SHIFTED(N, EVAL, e));
            }

            result_type invoke(
                typename impl2::expr_param e
              , typename impl2::state_param s
              , typename impl2::data_param d
              , mpl::true_
            ) const
            {
                #define M0(Z, M, e) BOOST_PP_COMMA_IF(BOOST_PP_SUB(M, 2)) EVAL(Z, M, e)
                BOOST_PROTO_USE_GET_POINTER();
                typedef typename detail::classtypeof<function_type>::type class_type;
                return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, e)) ->* EVAL(~, 0, e))(
                    BOOST_PP_REPEAT_FROM_TO(2, N, M0, e)
                );
                #undef M0
            }
        };

    #undef N

#endif

max_stars_repo_name: EricBoittier/vina-carb-docker

max_issues_repo_name: EricBoittier/vina-carb-docker

max_forks_repo_name: EricBoittier/vina-carb-docker


text:
#include "Analysis.h"

#include "Processing.h"

#include <unordered_map>

#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics.hpp>

template<typename T>
std::common_type_t<T, double> vectorNthElement(std::vector<T> &data, int32_t n)
{
    assert(n >= 0 && n < data.size());
    std::nth_element(data.begin(), data.begin() + n, data.end());
    return data[n];
}

template<typename T>
std::common_type_t<T, double> vectorQuantile(std::vector<T> &data, double q = 0.5)
{
    assert(!data.empty());

    if(q >= 1.0)
        return *std::max_element(data.begin(), data.end());
    if(q <= 0)
        return *std::min_element(data.begin(), data.end());

    q = std::clamp(q, 0.0, 1.0);
    const double n = data.size() * q - 0.5;
    const int n1 = static_cast<int>(std::floor(n));
    const int n2 = static_cast<int>(std::ceil(n));
    const auto t = n - n1;
    std::nth_element(data.begin(), data.begin() + n1, data.end());
    std::nth_element(data.begin() + n1, data.begin() + n2, data.end());
    return lerp<double>(data[n1], data[n2], t);
}

template<arrow::Type::type id>
std::shared_ptr<arrow::Table> countValueTyped(const arrow::Column &column)
{
    using T = typename TypeDescription<id>::ObservedType;
    using ArrowType = typename TypeDescription<id>::ArrowType;
    using Builder = typename TypeDescription<id>::BuilderType;
    std::unordered_map<T, int64_t> valueCounts;

    iterateOver<id>(column,
        [&] (auto &&elem) { valueCounts[elem]++; },
        [] () {});

    auto valueBuilder = makeBuilder(std::static_pointer_cast<ArrowType>(column.field()->type()));
    arrow::Int64Builder countBuilder;

    valueBuilder->Reserve(valueCounts.size());
    countBuilder.Reserve(valueCounts.size());

    for(auto && [value, count] : valueCounts)
    {
        append(*valueBuilder, value);
        append(countBuilder, count);
    }

    if(column.null_count())
    {
        valueBuilder->AppendNull();
        countBuilder.Append(column.null_count());
    }

    auto valueArray = finish(*valueBuilder);
    auto countArray = finish(countBuilder);

    auto valueColumn = std::make_shared<arrow::Column>(arrow::field("value", column.type(), column.null_count()), valueArray);
    auto countColumn = std::make_shared<arrow::Column>(arrow::field("count", countArray->type(), false), countArray);

    return tableFromArrays({valueArray, countArray}, {"value", "count"});
}

template<typename T>
constexpr bool doesAggregatorAllowsType(AggregateFunction aggregator)
{
    // element counter doesn't care what element is
    if(aggregator == AggregateFunction::Length)
        return true;

    return std::is_arithmetic_v<T>;
}

template<typename T>
struct Minimum
{
    T accumulator = std::numeric_limits<T>::max();
    static constexpr const char *name = "min";
    static constexpr int32_t RequiredSampleCount = 1;
    void operator() (T elem) { accumulator = std::min<T>(accumulator, elem); }
    void operator() () {}
    auto get() { return accumulator; }
};

template<typename T>
struct Maximum
{
    T accumulator = std::numeric_limits<T>::min();
    static constexpr const char *name = "max";
    static constexpr int32_t RequiredSampleCount = 1;
    void operator() (T elem) { accumulator = std::max<T>(accumulator, elem); }
    void operator() () {}
    auto get() { return accumulator; }
};

// TODO naive implementation, look for something numerically better
template<typename T>
struct Mean
{
    int64_t count = 0;
    T accumulator = 0;
    static constexpr const char *name = "mean";
    static constexpr int32_t RequiredSampleCount = 1;
    void operator() (T elem) { accumulator += elem; count++; }
    void operator() () {}
    auto get() { return accumulator / (double)count; }
};

template<typename T>
struct Median
{
    std::vector<T> values;

    static constexpr const char *name = "median";
    static constexpr int32_t RequiredSampleCount = 1;
    void operator() (T elem) { values.push_back(elem); }
    void operator() () {}
    auto get() { return vectorQuantile(values, 0.5); }
};

template<typename T>
struct Variance
{
    boost::accumulators::accumulator_set<T, boost::accumulators::features<boost::accumulators::tag::variance>> accumulator;

    static constexpr const char *name = "variance";
    static constexpr int32_t RequiredSampleCount = 2;
    void operator() (T elem) { accumulator(elem); }
    void operator() () {}
    auto get() { return boost::accumulators::variance(accumulator); }
};

template<typename T>
struct StdDev : Variance<T>
{
    static constexpr const char *name = "std dev";
    auto get() { return std::sqrt(Variance<T>::get()); }
};

template<typename T>
struct Sum : Variance<T>
{
    T accumulator{};
    static constexpr const char *name = "sum";
    static constexpr int32_t RequiredSampleCount = 0;
    void operator() (T elem) { accumulator += elem; }
    void operator() () {}
    T get() { return accumulator; }
};

struct Length
{
    int64_t length = 0;
    static constexpr const char *name = "length";
    static constexpr int32_t RequiredSampleCount = 0;

    template<typename T>
    void operator()(T &&)
    {
        length++;
    }
    void operator()()
    {
        length++;
    }

    int64_t get() { return length; }
};

template<typename T>
struct First
{
    std::optional<T> value;
    static constexpr const char *name = "first";
    static constexpr int32_t RequiredSampleCount = 1;

    void operator()(T t)
    {
        if(!value)
            value = t;
    }
    void operator() () {}
    T get() { return value.value_or(T{}); }
};

template<typename T>
struct Last
{
    T value{};
    static constexpr const char *name = "last";
    static constexpr int32_t RequiredSampleCount = 1;

    void operator()(T t)
    {
        value = t;
    }
    void operator() () {}
    T get() { return value; }

};

template<typename T>
struct RSI
{
    static constexpr const char *name = "RSI";
    static constexpr int32_t RequiredSampleCount = 1;

    Mean<T> down, up;

    void operator()(T value)
    {
        up(std::max<T>(value, 0.0));
        down(std::min<T>(0.0, value));
    }
    void operator() () {}

    double get()
    {
        const auto upMean = up.get();
        const auto downMean = down.get();
        return 100.0 * upMean / (upMean - downMean);
    }

};

template<AggregateFunction aggr, typename T>
struct AggregatorFor {};

template<typename T> struct AggregatorFor<AggregateFunction::Minimum, T> { using type = Minimum<T>; };
template<typename T> struct AggregatorFor<AggregateFunction::Maximum, T> { using type = Maximum<T>; };
template<typename T> struct AggregatorFor<AggregateFunction::Mean   , T> { using type = Mean<T>   ; };
template<typename T> struct AggregatorFor<AggregateFunction::Length , T> { using type = Length    ; };
template<typename T> struct AggregatorFor<AggregateFunction::Median , T> { using type = Median<T> ; };
template<typename T> struct AggregatorFor<AggregateFunction::First  , T> { using type = First<T>  ; };
template<typename T> struct AggregatorFor<AggregateFunction::Last   , T> { using type = Last<T>   ; };
template<typename T> struct AggregatorFor<AggregateFunction::Sum    , T> { using type = Sum<T>    ; };
template<typename T> struct AggregatorFor<AggregateFunction::RSI    , T> { using type = RSI<T>    ; };
template<typename T> struct AggregatorFor<AggregateFunction::StdDev , T> { using type = StdDev<T> ; };

template<arrow::Type::type id, typename Processor>
auto calculateStatScalar(const arrow::Column &column, Processor &p)
{
    iterateOver<id>(column,
        [&] (auto elem) { p(toStorage(elem)); },
        [] {});

    return p.get();
}

// Helper for providing fast path for single-chunked column index accessing
template<typename F>
auto dispatchIndexable(const std::shared_ptr<arrow::Column> &column, F &&f)
{
    if(column->data()->num_chunks() == 1)
        return f(column->data()->chunk(0));
    else
        return f(column);
}

/// workaround for VS 15.9 regression, see function below
template<template <typename> typename Processor>
struct CalculateStatVisitor
{
    const arrow::Column &column;
    CalculateStatVisitor(const arrow::Column &column) : column(column) {}

    std::shared_ptr<arrow::Column> operator()(std::integral_constant<arrow::Type::type, arrow::Type::STRING> id) const
    {
        THROW("Operation {} not supported for type {}", Processor<double>::name, column.type()->ToString());
    }
    std::shared_ptr<arrow::Column> operator()(std::integral_constant<arrow::Type::type, arrow::Type::TIMESTAMP> id) const
    {
        THROW("Operation {} not supported for type {}", Processor<double>::name, column.type()->ToString());
    }

    template<typename IDType>
    std::shared_ptr<arrow::Column> operator()(IDType id) const
    {
        using T = typename TypeDescription<id.value>::ValueType;
        Processor<T> p;
        using ResultT = decltype(p.get());

        if (column.length() - column.null_count() <= 0)
            return toColumn(std::vector<std::optional<ResultT>>{std::nullopt}, p.name);

        const auto result = calculateStatScalar<id.value>(column, p);
        return toColumn(std::vector<ResultT>{result}, { p.name });
    }
};

template<template <typename> typename Processor>
std::shared_ptr<arrow::Column> calculateStat(const arrow::Column &column)
{
    // workaround for VS 15.9 regression, see https://developercommunity.visualstudio.com/content/problem/395993/159-regression-error-on-valid-c-code-constexpr-if.html
    // FIXME restore code commented out as soon as our CI uses VS 15.8 or 16.0
    return visitType(*column.type(), CalculateStatVisitor<Processor>(column));
//     return visitType(*column.type(), [&](auto id) -> std::shared_ptr<arrow::Column>
//     {
//         if constexpr(id.value != arrow::Type::STRING && id.value != arrow::Type::TIMESTAMP)
//         {
//             using T = typename TypeDescription<id.value>::ValueType;
//             Processor<T> p;
//             using ResultT = decltype(p.get());
//
//             if(column.length() - column.null_count() <= 0)
//                 return toColumn(std::vector<std::optional<ResultT>>{std::nullopt}, p.name);
//
//             const auto result = calculateStatScalar<id.value>(column, p);
//             return toColumn(std::vector<ResultT>{result}, { p.name });
//         }
//         else
//             THROW("Operation {} not supported for type {}", Processor<double>::name, column.type()->ToString());
//     });
}

std::shared_ptr<arrow::Column> calculateQuantile(const arrow::Column &column, double q, std::string name)
{
    // return calculateStat<Median>(column);
    auto v = toJustVector(column);
    return visit([&] (auto &vector) -> std::shared_ptr<arrow::Column>
    {
        using VectorType = std::decay_t<decltype(vector)>;
        using T = typename VectorType::value_type;
        if constexpr(std::is_arithmetic_v<T>)
        {
            auto result = vectorQuantile(vector, q);
            return scalarToColumn(result, name);
        }
        else
            throw std::runtime_error(name + " is allowed only for arithmetics type");
    }, v);
}

std::shared_ptr<arrow::Table> countValues(const arrow::Column &column)
{
    return visitType(*column.type(), [&] (auto id)
    {
        return countValueTyped<id.value>(column);
    });
}

std::shared_ptr<arrow::Column> calculateMin(const arrow::Column &column)
{
    return calculateStat<Minimum>(column);
}

std::shared_ptr<arrow::Column> calculateMax(const arrow::Column &column)
{
    return calculateStat<Maximum>(column);
}

std::shared_ptr<arrow::Column> calculateMean(const arrow::Column &column)
{
    return calculateStat<Mean>(column);
}

std::shared_ptr<arrow::Column> calculateMedian(const arrow::Column &column)
{
    return calculateQuantile(column, 0.5, "median");
}

std::shared_ptr<arrow::Column> calculateQuantile(const arrow::Column &column, double q)
{
    return calculateQuantile(column, q, "quantile " + std::to_string(q));
}

std::shared_ptr<arrow::Array> fromMemory(double *data, int32_t dataCount)
{
    arrow::DoubleBuilder builder;
    builder.AppendValues(data, dataCount);
    return finish(builder);
}

std::shared_ptr<arrow::Column> columnFromArray(std::shared_ptr<arrow::Array> array, std::string name)
{
    auto field = arrow::field(name, array->type(), array->null_count());
    return std::make_shared<arrow::Column>(field, array);
}

std::shared_ptr<arrow::Column> calculateVariance(const arrow::Column &column)
{
    return calculateStat<Variance>(column);
}

std::shared_ptr<arrow::Column> calculateRSI(const arrow::Column &column)
{
    return calculateStat<RSI>(column);
}

std::shared_ptr<arrow::Column> calculateStandardDeviation(const arrow::Column &column)
{
    return calculateStat<StdDev>(column);
}

std::shared_ptr<arrow::Column> calculateSum(const arrow::Column &column)
{
    return calculateStat<Sum>(column);
}

double calculateCorrelation(const arrow::Column &xCol, const arrow::Column &yCol)
{
    if(xCol.null_count() >= xCol.length() || yCol.null_count() >= yCol.length())
        return std::numeric_limits<double>::quiet_NaN();

    struct CorrelationStats
    {
        double sumX = 0;
        double sumY = 0;
        double sumXX = 0;
        double sumYY = 0;
        double sumXY = 0;
        int64_t n = 0;

        void addPair(double xVal, double yVal)
        {
            sumX += xVal;
            sumY += yVal;
            sumXX += xVal * xVal;
            sumYY += yVal * yVal;
            sumXY += xVal * yVal;
            n++;
        }

        double correlation() const
        {
            const auto num = n * sumXY - sumX * sumY;
            const auto den = std::sqrt(n * sumXX - (sumX*sumX)) * std::sqrt(n * sumYY - (sumY*sumY));
            return num / den;
        }
    };

    auto stats = visitType(*xCol.type(), [&] (auto id1)
    {
        return visitType(*yCol.type(), [&] (auto id2) -> CorrelationStats
        {
            if constexpr(id1.value != arrow::Type::STRING  &&  id2.value != arrow::Type::STRING)
            {
                CorrelationStats stats;
                iterateOverJustPairs<id1.value, id2.value>(xCol, yCol,
                    [&] (auto xVal, auto yVal)
                {
                    stats.addPair(toStorage(xVal), toStorage(yVal));
                });
                return stats;
            }
            else
                throw std::runtime_error("Correlation not supported on string types");
        });
    });

    return stats.correlation();
}

std::shared_ptr<arrow::Column> calculateCorrelation(const arrow::Table &table, const arrow::Column &column)
{
    if(table.num_rows() != column.length())
        throw std::runtime_error("cannot calculate correlation: mismatched column/table row counts");

    const auto N = table.num_columns();
    std::vector<double> correlationValues;
    correlationValues.resize(N);

    for(int i = 0; i < N; i++)
    {
        const auto columnI = table.column(i);
        const auto isSelfCompare = &column == columnI.get();
        correlationValues[i] = isSelfCompare
            ? 1.0
            : calculateCorrelation(column, *columnI);
    }

    return toColumn(correlationValues, column.name() + "_CORR");
}

std::shared_ptr<arrow::Table> calculateCorrelationMatrix(const arrow::Table &table)
{
    const auto N = table.num_columns();
    std::vector<std::vector<double>> correlationMatrix;
    correlationMatrix.resize(N);
    for(auto &correlationColumn : correlationMatrix)
        correlationColumn.resize(N);

    for(int i = 0; i < N; i++)
    {
        const auto ci = table.column(i);
        correlationMatrix[i][i] = 1.0;
        for(int j = i + 1; j < N; j++)
        {
            const auto cj = table.column(j);
            const auto correlation = calculateCorrelation(*ci, *cj);
            correlationMatrix[i][j] = correlation;
            correlationMatrix[j][i] = correlation;
        }
    }

    std::vector<std::shared_ptr<arrow::Column>> ret;
    for(int i = 0; i < N; i++)
    {
        auto c = toColumn(correlationMatrix.at(i), table.column(i)->name());
        ret.push_back(c);
    }

    return tableFromColumns(ret);
}

double autoCorrelation(const std::shared_ptr<arrow::Column> &column, int64_t lag /*= 1*/)
{
    auto shiftedColumn = shift(column, lag);
    auto debug = toVector<std::optional<int64_t>>(*shiftedColumn);
    return calculateCorrelation(*column, *shiftedColumn);
}

template<typename T>
struct AggregateBase
{
    virtual ~AggregateBase(){}

    virtual void operator()(T t) = 0;
    virtual void operator()() = 0;
    virtual std::optional<double> get(bool hadValidValue) = 0;
    virtual std::string name() = 0;
};

template<typename T, typename Aggregator>
struct AggregateBy : AggregateBase<T>
{
    Aggregator a;

    virtual void operator()(T t) override
    {
        a(t);
    }
    virtual void operator()() override
    {
        a();
    }
    virtual std::optional<double> get(bool hadValidValue) override
    {
        if(hadValidValue || !Aggregator::RequiredSampleCount)
            return a.get();
        return {};
    }
    virtual std::string name() override
    {
        return Aggregator::name;
    }
};

template<AggregateFunction aggr, typename T>
using AggregatorFor_t = typename AggregatorFor<aggr, T>::type;

template<typename T>
std::unique_ptr<AggregateBase<T>> makeAggregator(AggregateFunction a)
{
    return dispatchAggregateByEnum(a, [] (auto aggrC) -> std::unique_ptr<AggregateBase<T>>
    {
        using Aggregator = AggregatorFor_t<aggrC.value, T>;
        if constexpr(doesAggregatorAllowsType<T>(aggrC.value))
            return std::make_unique<AggregateBy<T, Aggregator>>();
        else
            THROW("wrong type for function id={}", (int)aggrC.value);
    });
}

std::string aggregateName(AggregateFunction a)
{
    // inefficient, but should not be called that often
    return makeAggregator<double>(a)->name();
}

template<typename T>
struct Aggregators
{
    bool hadValidValue = false;
    std::vector<std::unique_ptr<AggregateBase<T>>> aggregators;
    Aggregators(const std::vector<AggregateFunction> &toAggregate)
    {
        aggregators = transformToVector(toAggregate, [](auto aggrEnum) { return makeAggregator<T>(aggrEnum); });
    }
    void operator()(T t)
    {
        hadValidValue = true;
        for(auto &a : aggregators)
            (*a)(t);
    }
    void operator()()
    {
        for(auto &a : aggregators)
            (*a)();
    }
};

// Cannot be just lambda because of GCC-8 bug
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86740
template<typename ArrowType, typename T>
struct AbominableGroupingIterator
{
    int64_t row = 0;

    GroupedKeyInfo<ArrowType> &groups;
    std::vector<Aggregators<T>> &aggregators;

    AbominableGroupingIterator(GroupedKeyInfo<ArrowType> &groups, std::vector<Aggregators<T>> &aggregators)
            : groups(groups), aggregators(aggregators)
    {}

    template <typename U>
    void operator()(U value)
    {
        const auto groupId = groups.groupIds[row++];
        aggregators[groupId](value);
    }
    void operator()()
    {
        const auto groupId = groups.groupIds[row++];
        aggregators[groupId]();
    }
};

std::string to_string(AggregateFunction a)
{
    return dispatchAggregateByEnum(a, [] (auto aggrC) { return AggregatorFor_t<aggrC.value, double>::name; });
}

DFH_EXPORT std::shared_ptr<arrow::Table> abominableGroupAggregate(std::shared_ptr<arrow::Column> keyColumn, std::vector<std::pair<std::shared_ptr<arrow::Column>, std::vector<AggregateFunction>>> toAggregate)
{
    std::vector<std::shared_ptr<arrow::Column>> newColumns;

    visitDataType(keyColumn->type(), [&](auto type)
    {
        using ArrowType = ArrowTypeFromPtr<decltype(type)>;
        constexpr auto keyTypeID = idFromDataPointer<decltype(type)>;
        using KeyT = typename TypeDescription<keyTypeID>::ObservedType;
        if constexpr(keyTypeID == arrow::Type::LIST)
        {
            throw std::runtime_error("not implemented: grouping by column of list type");
        }
        else
        {
            GroupedKeyInfo<ArrowType> groups{*keyColumn};

            const auto groupCount = groups.groupCount();
            const auto hasNulls = groups.hasNulls;
            const auto afterLastGroup = groups.uniqueValues.size()+1;

            std::vector<KeyT> keyValues(afterLastGroup);
            for(auto [keyValue, groupId] : groups.uniqueValues)
                keyValues[groupId] = keyValue;

            // build column with unique key values
            {
                auto builder = makeBuilder(type);
                if(hasNulls)
                    builder->AppendNull();
                for(int group = 1; group < keyValues.size(); ++group)
                    append(*builder, keyValues[group]);

                auto arr = finish(*builder);
                newColumns.push_back(std::make_shared<arrow::Column>(keyColumn->field(), arr));
            }

            // build column for each (column, aggregate function) pair
            for(auto &colAggrs : toAggregate)
            {
                visitType(colAggrs.first->type()->id(), [&](auto id)
                {
                    auto [column, aggregates] = colAggrs;
                    using T = typename TypeDescription<id.value>::ObservedType;
                    std::vector<Aggregators<T>> aggregators;
                    aggregators.reserve(afterLastGroup);
                    for(int i = 0; i < afterLastGroup; i++)
                    {
                        try
                        {
                            aggregators.emplace_back(aggregates);
                        }
                        catch(std::exception &e)
                        {
                            THROW("cannot aggregate for column `{}` of type `{}`: {}", column->name(), column->type()->ToString(), e);
                        }
                    }

                    AbominableGroupingIterator<ArrowType, T> iterator{groups, aggregators};
                    iterateOver<id.value>(*column, iterator, iterator);

                    std::vector<arrow::DoubleBuilder> newColumnBuilders(aggregates.size());
                    for(auto &&newColumnBuilder : newColumnBuilders)
                        newColumnBuilder.Reserve(groupCount);

                    for(int64_t groupItr = !hasNulls; groupItr < afterLastGroup; ++groupItr)
                    {
                        auto &aggr = aggregators[groupItr];
                        for(int32_t i = 0; i < aggregates.size(); i++)
                        {
                            if(auto result = aggr.aggregators[i]->get(aggr.hadValidValue))
                                newColumnBuilders[i].Append(*result);
                            else
                                newColumnBuilders[i].AppendNull();
                        }
                    }
                    for(int32_t i = 0; i < aggregates.size(); i++)
                    {
                        auto arr = finish(newColumnBuilders[i]);
                        auto col = toColumn(arr, column->name() + "_"s + aggregateName(aggregates[i]));
                        newColumns.push_back(col);
                    };
                });
            }
        }
    });

    return tableFromColumns(newColumns);
}

template<class TD>
using IntervalType = typename TD::IntervalType;

template<arrow::Type::type id, typename Indexable, typename Index>
std::optional<typename TypeDescription<id>::ObservedType> getMaybeValue(const Indexable &indexable, Index index)
{
    if constexpr(std::is_same_v<Indexable, arrow::Column>)
    {
        return getMaybeValue<id>(*indexable.data(), index);
    }
    else if constexpr(std::is_same_v<Indexable, arrow::ChunkedArray>)
    {
        auto [chunk, chunkIndex] = locateChunk(indexable, index);
        return getMaybeValue<id>(*chunk, index);
    }
    else if constexpr(std::is_same_v<Indexable, arrow::Array>)
    {
        if(indexable.IsValid(index))
            return arrayValueAt<id>(indexable, index);
        else
            return std::nullopt;
    }
    else
        static_assert(always_false_v<Indexable>);
}

template<arrow::Type::type id, typename Indexable>
auto getJustValue(const Indexable &indexable, int64_t index)
{
    if constexpr(std::is_same_v<Indexable, arrow::Column>)
        return columnValueAt<id>(indexable, index);
    else if constexpr(std::is_same_v<Indexable, arrow::Array>)
        return arrayValueAt<id>(indexable, index);
    else
        static_assert(always_false_v<Indexable>);
}

template<typename Indexable>
std::vector<int64_t> collectRollingWindowPositionsT(const Indexable &indexable, DynamicField interval)
{
    const auto N = indexable.length();
    std::vector<int64_t> ret(N);

    visitType4(indexable.type(), [&](auto id)
    {
        if constexpr(is_detected_v<IntervalType, TypeDescription<id.value>>)
        {
            using TD = TypeDescription<id.value>;
            using Array = typename TD::Array;
            using IntervalType = IntervalType<TD>;

            if(!holds_alternative<IntervalType>(interval))
                THROW("wrong interval type: `index {}`, expected: `{}`", interval.index(), typeid(IntervalType));

            const auto intervalT = get<IntervalType>(interval);
            int64_t left = 0;

            for(int64_t right = 0; right < N; ++right)
            {
                const auto rightValue = getJustValue<id.value>(indexable, right);
                const auto leftValue = rightValue - intervalT;

                while(left < right && getJustValue<id.value>(indexable, left) <= leftValue)
                    left++;

                ret[right] = 1 + right - left;
            }
        }
        else
            throw std::runtime_error("interval windows not supported for type " + indexable.type()->ToString());
    });

    return ret;
}

// because of GCC-8 bug this cannot be lambda
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86740
template <typename Indexable, arrow::Type::type id>
struct FunctionOverWindowCalculator
{
    const Indexable &indexable;
    int64_t startIndex;
    int64_t windowsWidth;

    template <AggregateFunction f>
    std::optional<double> operator()(std::integral_constant<AggregateFunction, f> aggrC) const
    {
        using T = typename TypeDescription<id>::ValueType;
        using Aggregator = AggregatorFor_t<aggrC.value, T>;
        Aggregator aggregator;

        auto validCount = 0;
        for(int64_t row = startIndex - windowsWidth + 1; row <= startIndex; ++row)
        {
            const auto value = getMaybeValue<id>(indexable, row);
            if(value)
            {
                ++validCount;
                aggregator(*value);
            }
            else
                aggregator();
        }
        if(validCount >= Aggregator::RequiredSampleCount)
            return aggregator.get();
        else
            return std::nullopt;
    }
};

template<typename Indexable>
std::optional<double> calculateFunctionOnWindow(const Indexable &indexable, int64_t startIndex, int64_t windowsWidth, AggregateFunction f)
{
    return visitType4(indexable.type(), [&] (auto id) -> std::optional<double>
    {
        if constexpr(id.value == arrow::Type::INT64 || id.value == arrow::Type::DOUBLE)
        {
            FunctionOverWindowCalculator<Indexable, id.value> calculator{indexable, startIndex, windowsWidth};
            return dispatchAggregateByEnum(f, calculator);
        }
        else
            throw std::runtime_error("rolling statistics not supported for type " + indexable.type()->ToString());
    });
}

std::vector<int64_t> collectRollingIntervalSizes(std::shared_ptr<arrow::Column> keyColumn, DynamicField interval)
{
    try
    {
        return dispatchIndexable(keyColumn, [&] (auto &&indexable)
        {
            return collectRollingWindowPositionsT(*indexable, interval);
        });
    }
    catch(std::exception &e)
    {
        THROW("failed to collect window widths for column `{}` of type `{}`: {}", keyColumn->name(), keyColumn->type()->ToString(), e);
    }
}

void requireSameSize(const arrow::Column &lhs, const arrow::Column &rhs)
{
    auto lhsN = lhs.length();
    auto rhsN = rhs.length();

    if(lhsN != rhsN)
        THROW("Column length mismatch: `{}` has {} rows, `{}` has {} rows", lhs.name(), lhsN, rhs.name(), rhsN);
}

std::shared_ptr<arrow::Table> rollingInterval(std::shared_ptr<arrow::Column> keyColumn, DynamicField interval, std::vector<std::pair<std::shared_ptr<arrow::Column>, std::vector<AggregateFunction>>> toAggregate)
{
    std::vector<std::shared_ptr<arrow::Column>> newColumns{ keyColumn };

    const auto N = keyColumn->length();
    const auto windowWidths = collectRollingIntervalSizes(keyColumn, interval);
    for(auto && [col, funcs] : toAggregate)
    {
        requireSameSize(*keyColumn, *col);
        dispatchIndexable(col, [&, &col=col, &funcs=funcs](auto &&indexable)
        {
            const auto &name = col->name();
            for(auto fun : funcs)
            {
                try
                {
                    arrow::DoubleBuilder builder;
                    builder.Reserve(N);

                    for(int64_t row = 0; row < N; ++row)
                    {
                        auto value = calculateFunctionOnWindow(*indexable, row, windowWidths[row], fun);
                        append(builder, value);
                    }

                    auto arr = finish(builder);
                    newColumns.push_back(toColumn(arr, name + "_" + to_string(fun)));  // TODO pretty name
                }
                catch(std::exception &e)
                {
                    THROW("failed to calculate `{}` on column `{}`: {}", to_string(fun), name, e);
                }
            }
        });
    }

    return tableFromColumns(newColumns);
}

ext: cpp

max_stars_repo_name: Magalame/dataframes

max_issues_repo_name: Magalame/dataframes

max_forks_repo_name: Magalame/dataframes


text:
#include <vector>
#include <sensor_msgs/NavSatFix.h>
#include <ros/ros.h>
#include <boost/bind.hpp>
#include <string>
#include <cmath>
#include <iostream>
#include <ios>
#include <iosfwd>
#include <fstream>
#include <iomanip>

static const int buffer_size = 10;
static const int loop_rate_hz = 10;

sensor_msgs::NavSatFix current_gps;

void setCurrentGPS(sensor_msgs::NavSatFix sensor_gps) {
    current_gps = sensor_gps;
}

int main(int argc, char* argv[]) {
    int file_count, i, no_of_waypoints, count;
    std::string c;
    sensor_msgs::NavSatFix term, temp;
    std::string num_file, txtfile_add, file_num_str;
    std::fstream numfile, waypoints_file, edit_numfile;
    std::vector<sensor_msgs::NavSatFix> waypoints_vector;
    sensor_msgs::NavSatFix temp_pair;

    std::cout.unsetf(std::ios::floatfield);
    std::cout.precision(16);

    ros::init(argc, argv, "waypoint_recorder");
    ros::NodeHandle node_handle;

    node_handle.getParam("/waypoint_recorder/data_file", num_file);
    node_handle.getParam("/waypoint_recorder/record_file_folder", txtfile_add);

    numfile.open(num_file.c_str());

    if (numfile.is_open()) {
        numfile>>file_count;
        std::stringstream ss;
        ss << file_count;
        file_num_str = ss.str();
        numfile.close();
    } else {
        file_count = 0;
        numfile.close();
    }
    std::cout << "Enter the no of waypoints:";
    std::cin>>no_of_waypoints;
    std::cin.ignore(1, '\n');

    ros::Subscriber sub_current_gps = node_handle.subscribe("/vn_ins/fix", buffer_size, setCurrentGPS);

    ros::Rate loop_rate(loop_rate_hz);
    count = 0;
    while (ros::ok() && count < no_of_waypoints) {
        ros::spinOnce();
        for (i = 0, term.latitude = current_gps.latitude, term.longitude = current_gps.longitude; term.latitude != 0 && term.longitude != 0; ++i) {
            std::cout << "ENTER to record an entry\n'e' to end\nand 'n'(only after 'e') to close file when finished taking waypoints and make a txt." << std::endl;
            std::getline(std::cin, c);
            if (c == "") {
                std::cout << "Reading " << count + 1 << "th waypoint " << i + 1 << "th time." << std::endl;
                ros::spinOnce();
                temp = current_gps;
                std::cout << "latitude:" << temp.latitude << " " << "longitude:" << temp.longitude << std::endl;
                term.latitude = (((term.latitude * i) + temp.latitude) / (i + 1));
                term.longitude = (((term.longitude * i) + temp.longitude) / (i + 1));
                temp_pair.latitude = term.latitude;
                temp_pair.longitude = term.longitude;
                continue;
            } else if (c == "e") {
                std::cout << "\n";
                break;
            } else if (c == "n") {
                std::cout << "\n";
                break;
            }
        }
        if (c == "e") {
            waypoints_vector.push_back(temp_pair);
            count++;
            std::cout << "Read " << count << "th waypoint\n" << "Set to " << temp_pair.latitude << " " << temp_pair.longitude << "\n" << "Move to the next waypoint.\n" << std::endl;
            std::cout << "------------------------------------" << std::endl;
        } else if (c == "n") {
            break;
        }
    }
    edit_numfile.open(num_file.c_str(), std::ios::in | std::ios::out | std::ios::trunc);
    edit_numfile << ++file_count;
    edit_numfile.close();

    std::string record_file = (txtfile_add + "GPS_waypoints" + file_num_str + ".txt");
    std::cout << "Writing to " << record_file << std::endl;
    waypoints_file.open(record_file.c_str(), std::ios::in | std::ios::out | std::ios::trunc);
    waypoints_file << count << std::endl;
    for (std::vector <sensor_msgs::NavSatFix>::iterator it = waypoints_vector.begin(); it != waypoints_vector.end(); it++) {
        waypoints_file << std::setprecision(10) << it->latitude;
        waypoints_file << " ";
        waypoints_file << std::setprecision(10) << it->longitude << std::endl;
    }
    waypoints_file << "#mention this file in the launch of waypoint_selector." << std::endl;
    waypoints_file.close();
}

max_stars_repo_name: khairulislam/phys

max_issues_repo_name: khairulislam/phys

max_forks_repo_name: khairulislam/phys


text:
#include "evaluation.h"
#include "predeal.h"
#include <boost/graph/graph_concepts.hpp>

using namespace std;

Eigen::Vector3f posediff(const Eigen::Vector3f& x, const Eigen::Vector3f &y)
{
  Eigen::Vector3f v;
  v(0)=abs(x(0)-y(0));
  v(1)=abs(x(1)-y(1));
  float x2,y2;
  if(x(2)<0)
  {
    x2=2*M_PI+x(2);
  }
  else
  {
    x2=x(2);
  }
  if(y(2)<0)
  {
    y2=2*M_PI+y(2);
  }
  else
  {
    y2=y(2);
  }
  v(2)=abs(x2-y2);
  return v;
}

int main()
{
   string posedir="/home/shaoan/projects/slamEvaluation/data/rgspose.txt";
  vector<Eigen::Vector3f> v_pose;

  predeal::readposefile(posedir,v_pose);
  string maposedir="/home/shaoan/projects/slamEvaluation/data/maPose.txt";
  vector<Eigen::Vector3f> v_mapose;

  predeal::readposefile(maposedir,v_mapose);

 assert(v_mapose.size()==v_pose.size());
 assert(v_pose.size()>0);

     vector<Eigen::Vector3f> differnce;
     for(int i=0;i<v_pose.size();i++)
     {
       Eigen::Vector3f v;
       v=posediff(v_mapose[i],v_pose[i]);
       //v=v_mapose[i]-v_pose[i];
       //cout<<v<<endl;
       differnce.push_back(v);
    }

    evaluation eval(differnce);
    Eigen::Vector2f v2;
   v2= eval.computeMSE();
   cout<<"平均绝对误差："<<endl;
   cout<<v2<<endl;
   Eigen::Vector3f v3;
   v3=eval.computeMAE();
  cout<<"平均绝对误差："<<endl;
  cout<<v3<<endl;

}

max_stars_repo_name: zoumaguanxin/slamEvaluation

max_issues_repo_name: zoumaguanxin/slamEvaluation

max_forks_repo_name: zoumaguanxin/slamEvaluation


text:
// Copyright (c) 2005-2009 Jaroslav Gresula
//
// Distributed under the MIT license (See accompanying file
// LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt)
//

#include "testtools.h"
#include <boost/ptr_container/ptr_vector.hpp>
#include <core/jstd/dynlib.h>
#include <core/jstd/thread.h>
#include <stdio.h>
#include <assert.h>

using namespace jag::jstd;

//
// dynamical load stuff
typedef void (*library_fn_t)(void);
static library_fn_t active_lib = 0;

// thread function
//
void thread_fn()
{
    (*active_lib)();
    (*active_lib)();
    (*active_lib)();
}

//
// main entrypoint
//
void test_main()
{
# ifdef JAG_WIN32
    char const*const dllmytss_name = "dllmytss";
# else
    char const*const dllmytss_name = "libdllmytss";
# endif

    try
    {
        DynamicLibrary dll(dllmytss_name);
//         DynamicLibrary* pdll = new DynamicLibrary("dllmytss");
//         DynamicLibrary& dll = *pdll;

        active_lib = get_dll_symbol<library_fn_t>(dll, "dll_entrypoint");

        (*active_lib)();

        const int NUM_THREADS = 1;
        boost::ptr_vector<Thread> threads;
        threads.reserve(NUM_THREADS);

        for(int i=0; i<NUM_THREADS; ++i)
            threads.push_back(new Thread(thread_fn));

        for(int i=0; i<NUM_THREADS; ++i)
            threads[i].join();
    }
    catch(std::exception& exc)
    {
        fprintf(stderr, "ERROR: %s\n", exc.what());
        BOOST_ERROR("failed");
    }

    puts("[app] done");
}

//
//
//
int main()
{
    int result = guarded_test_run(test_main);
    result += boost::report_errors();
    return result;
}

// Dynamic Initialization and Destruction with Concurrency
// -------------------------------------------------------
// see: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html

// synchronized init (run_once, thread-safe singleton)
// - run_once is preferable, boost seems to have fast implementations
// - create a tss slot; the slot will hold a keyed list (map) of values
//
// --
//
// individual values must be keyed (by what - unique id, address of a shared obj)
// operations
// - get .. key
// - reset .. key, value_ptr, cleanup
// - release .. key (detaches value_ptr from tss)
//
//
// per-thread cleanup
// - must be called explicitly
// - or provided by platform (distinguish mingw and cygwin)
//
// --
//
// synchronized tss slot destruction
//
//
// ----
// - single cleanup function per type
// ?????
// - slot creation/deletion - can be done in ctor/dtor of global variable
//   - are all threads done by then (i.e. cleanup was called)
//   - cleanup for the main thread must be invoked explicitly
// - look into AllocHeap (used by boost for allocations)
// - dynamic unload
//   - not all threads are necessarily done
//

max_stars_repo_name: jgresula/jagpdf

max_issues_repo_name: jgresula/jagpdf

max_forks_repo_name: jgresula/jagpdf


text:
// Copyright (c) 2009-2016 The Bitcoin developers
// Copyright (c) 2016 The Klondike developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "txdb.h"
#include "main.h"
#include "uint256.h"

static const int nCheckpointSpan = 10;

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        ( 0,      hashGenesisBlock )

    ;

    // TestNet has no checkpoints
    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        (0, uint256("0x"))
        ;

    bool CheckHardened(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }

    // ppcoin: synchronized checkpoint (centrally broadcasted)
    uint256 hashSyncCheckpoint = 0;
    uint256 hashPendingCheckpoint = 0;
    CSyncCheckpoint checkpointMessage;
    CSyncCheckpoint checkpointMessagePending;
    uint256 hashInvalidCheckpoint = 0;
    CCriticalSection cs_hashSyncCheckpoint;

    // ppcoin: get last synchronized checkpoint
    CBlockIndex* GetLastSyncCheckpoint()
    {
        LOCK(cs_hashSyncCheckpoint);
        if (!mapBlockIndex.count(hashSyncCheckpoint))
            error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
        else
            return mapBlockIndex[hashSyncCheckpoint];
        return NULL;
    }

    // ppcoin: only descendant of current sync-checkpoint is allowed
    bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
    {
        if (!mapBlockIndex.count(hashSyncCheckpoint))
            return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
        if (!mapBlockIndex.count(hashCheckpoint))
            return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str());

        CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint];
        CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint];

        if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight)
        {
            // Received an older checkpoint, trace back from current checkpoint
            // to the same height of the received checkpoint to verify
            // that current checkpoint should be a descendant block
            CBlockIndex* pindex = pindexSyncCheckpoint;
            while (pindex->nHeight > pindexCheckpointRecv->nHeight)
                if (!(pindex = pindex->pprev))
                    return error("ValidateSyncCheckpoint: pprev null - block index structure failure");
            if (pindex->GetBlockHash() != hashCheckpoint)
            {
                hashInvalidCheckpoint = hashCheckpoint;
                return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
            }
            return false; // ignore older checkpoint
        }

        // Received checkpoint should be a descendant block of the current
        // checkpoint. Trace back to the same height of current checkpoint
        // to verify.
        CBlockIndex* pindex = pindexCheckpointRecv;
        while (pindex->nHeight > pindexSyncCheckpoint->nHeight)
            if (!(pindex = pindex->pprev))
                return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure");
        if (pindex->GetBlockHash() != hashSyncCheckpoint)
        {
            hashInvalidCheckpoint = hashCheckpoint;
            return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
        }
        return true;
    }

    bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
    {
        CTxDB txdb;
        txdb.TxnBegin();
        if (!txdb.WriteSyncCheckpoint(hashCheckpoint))
        {
            txdb.TxnAbort();
            return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
        }
        if (!txdb.TxnCommit())
            return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str());

        Checkpoints::hashSyncCheckpoint = hashCheckpoint;
        return true;
    }

    bool AcceptPendingSyncCheckpoint()
    {
        LOCK(cs_hashSyncCheckpoint);
        if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
        {
            if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
            {
                hashPendingCheckpoint = 0;
                checkpointMessagePending.SetNull();
                return false;
            }

            CTxDB txdb;
            CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
            if (!pindexCheckpoint->IsInMainChain())
            {
                CBlock block;
                if (!block.ReadFromDisk(pindexCheckpoint))
                    return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
                if (!block.SetBestChain(txdb, pindexCheckpoint))
                {
                    hashInvalidCheckpoint = hashPendingCheckpoint;
                    return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
                }
            }

            if (!WriteSyncCheckpoint(hashPendingCheckpoint))
                return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
            hashPendingCheckpoint = 0;
            checkpointMessage = checkpointMessagePending;
            checkpointMessagePending.SetNull();
            printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str());
            // relay the checkpoint
            if (!checkpointMessage.IsNull())
            {
                BOOST_FOREACH(CNode* pnode, vNodes)
                    checkpointMessage.RelayTo(pnode);
            }
            return true;
        }
        return false;
    }

    // Automatically select a suitable sync-checkpoint
    uint256 AutoSelectSyncCheckpoint()
    {
        const CBlockIndex *pindex = pindexBest;
        // Search backward for a block within max span and maturity window
        while (pindex->pprev && (pindex->GetBlockTime() + nCheckpointSpan * nTargetSpacing > pindexBest->GetBlockTime() || pindex->nHeight + nCheckpointSpan > pindexBest->nHeight))
            pindex = pindex->pprev;
        return pindex->GetBlockHash();
    }

    // Check against synchronized checkpoint
    bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
    {
        if (fTestNet) return true; // Testnet has no checkpoints
        int nHeight = pindexPrev->nHeight + 1;

        LOCK(cs_hashSyncCheckpoint);
        // sync-checkpoint should always be accepted block
        assert(mapBlockIndex.count(hashSyncCheckpoint));
        const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];

        if (nHeight > pindexSync->nHeight)
        {
            // trace back to same height as sync-checkpoint
            const CBlockIndex* pindex = pindexPrev;
            while (pindex->nHeight > pindexSync->nHeight)
                if (!(pindex = pindex->pprev))
                    return error("CheckSync: pprev null - block index structure failure");
            if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
                return false; // only descendant of sync-checkpoint can pass check
        }
        if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
            return false; // same height with sync-checkpoint
        if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
            return false; // lower height than sync-checkpoint
        return true;
    }

    bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
    {
        LOCK(cs_hashSyncCheckpoint);
        if (hashPendingCheckpoint == 0)
            return false;
        if (hashBlock == hashPendingCheckpoint)
            return true;
        if (mapOrphanBlocks.count(hashPendingCheckpoint)
            && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint]))
            return true;
        return false;
    }

    // ppcoin: reset synchronized checkpoint to last hardened checkpoint
    bool ResetSyncCheckpoint()
    {
        LOCK(cs_hashSyncCheckpoint);
        const uint256& hash = mapCheckpoints.rbegin()->second;
        if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
        {
            // checkpoint block accepted but not yet in main chain
            printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str());
            CTxDB txdb;
            CBlock block;
            if (!block.ReadFromDisk(mapBlockIndex[hash]))
                return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str());
            if (!block.SetBestChain(txdb, mapBlockIndex[hash]))
            {
                return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str());
            }
        }
        else if(!mapBlockIndex.count(hash))
        {
            // checkpoint block not yet accepted
            hashPendingCheckpoint = hash;
            checkpointMessagePending.SetNull();
            printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
        }

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
        {
            const uint256& hash = i.second;
            if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
            {
                if (!WriteSyncCheckpoint(hash))
                    return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str());
                printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str());
                return true;
            }
        }

        return false;
    }

    void AskForPendingSyncCheckpoint(CNode* pfrom)
    {
        LOCK(cs_hashSyncCheckpoint);
        if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
            pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
    }

    bool SetCheckpointPrivKey(std::string strPrivKey)
    {
        // Test signing a sync-checkpoint with genesis block
        CSyncCheckpoint checkpoint;
        checkpoint.hashCheckpoint = !fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet;
        CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
        sMsg << (CUnsignedSyncCheckpoint)checkpoint;
        checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());

        std::vector<unsigned char> vchPrivKey = ParseHex(strPrivKey);
        CKey key;
        key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
        if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
            return false;

        // Test signing successful, proceed
        CSyncCheckpoint::strMasterPrivKey = strPrivKey;
        return true;
    }

    bool SendSyncCheckpoint(uint256 hashCheckpoint)
    {
        CSyncCheckpoint checkpoint;
        checkpoint.hashCheckpoint = hashCheckpoint;
        CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
        sMsg << (CUnsignedSyncCheckpoint)checkpoint;
        checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());

        if (CSyncCheckpoint::strMasterPrivKey.empty())
            return error("SendSyncCheckpoint: Checkpoint master key unavailable.");
        std::vector<unsigned char> vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey);
        CKey key;
        key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
        if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
            return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?");

        if(!checkpoint.ProcessSyncCheckpoint(NULL))
        {
            printf("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n");
            return false;
        }

        // Relay checkpoint
        {
            LOCK(cs_vNodes);
            BOOST_FOREACH(CNode* pnode, vNodes)
                checkpoint.RelayTo(pnode);
        }
        return true;
    }

    // Is the sync-checkpoint outside maturity window?
    bool IsMatureSyncCheckpoint()
    {
        LOCK(cs_hashSyncCheckpoint);
        // sync-checkpoint should always be accepted block
        assert(mapBlockIndex.count(hashSyncCheckpoint));
        const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
        return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity ||
                pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime());
    }
}

// ppcoin: sync-checkpoint master key
const std::string CSyncCheckpoint::strMasterPubKey = "0481826bb909d0bc1f31b72ba150d635b42e775403db4343bd57f9bff6245641b8b7d211856bd587fc2b17186d7a892ce01f796c5deebf3cf933b635475ba53631";

std::string CSyncCheckpoint::strMasterPrivKey = "";

// ppcoin: verify signature of sync-checkpoint message
bool CSyncCheckpoint::CheckSignature()
{
    CKey key;
    if (!key.SetPubKey(ParseHex(CSyncCheckpoint::strMasterPubKey)))
        return error("CSyncCheckpoint::CheckSignature() : SetPubKey failed");
    if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
        return error("CSyncCheckpoint::CheckSignature() : verify signature failed");

    // Now unserialize the data
    CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
    sMsg >> *(CUnsignedSyncCheckpoint*)this;
    return true;
}

// ppcoin: process synchronized checkpoint
bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
{
    if (!CheckSignature())
        return false;

    LOCK(Checkpoints::cs_hashSyncCheckpoint);
    if (!mapBlockIndex.count(hashCheckpoint))
    {
        // We haven't received the checkpoint chain, keep the checkpoint as pending
        Checkpoints::hashPendingCheckpoint = hashCheckpoint;
        Checkpoints::checkpointMessagePending = *this;
        printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str());
        // Ask this guy to fill in what we're missing
        if (pfrom)
        {
            pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
            // ask directly as well in case rejected earlier by duplicate
            // proof-of-stake because getblocks may not get it this time
            pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
        }
        return false;
    }

    if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint))
        return false;

    CTxDB txdb;
    CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
    if (!pindexCheckpoint->IsInMainChain())
    {
        // checkpoint chain received but not yet main chain
        CBlock block;
        if (!block.ReadFromDisk(pindexCheckpoint))
            return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
        if (!block.SetBestChain(txdb, pindexCheckpoint))
        {
            Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
            return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
        }
    }

    if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint))
        return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str());
    Checkpoints::checkpointMessage = *this;
    Checkpoints::hashPendingCheckpoint = 0;
    Checkpoints::checkpointMessagePending.SetNull();
    printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str());
    return true;
}

max_stars_repo_name: klondikecrypto/klondike

max_issues_repo_name: klondikecrypto/klondike

max_forks_repo_name: klondikecrypto/klondike


text:
/**
 *    Copyright 2014 MongoDB Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the GNU Affero General Public License in all respects for
 *    all of the code used other than as permitted herein. If you modify file(s)
 *    with this exception, you may extend this exception to your version of the
 *    file(s), but you are not obligated to do so. If you do not wish to do so,
 *    delete this exception statement from your version. If you delete this
 *    exception statement from all source files in the program, then also delete
 *    it in the license file.
 */

#include "mongo/platform/basic.h"

#include <boost/filesystem.hpp>
#include <fstream>
#include <ostream>

#include "mongo/db/storage/storage_engine_lock_file.h"
#include "mongo/platform/process_id.h"
#include "mongo/unittest/temp_dir.h"
#include "mongo/unittest/unittest.h"

#ifndef _WIN32
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif

namespace {

using std::string;
using mongo::unittest::TempDir;

using namespace mongo;

TEST(StorageEngineLockFileTest, UncleanShutdownNoExistingFile) {
    TempDir tempDir("StorageEngineLockFileTest_UncleanShutdownNoExistingFile");
    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_FALSE(lockFile.createdByUncleanShutdown());
}

TEST(StorageEngineLockFileTest, UncleanShutdownEmptyExistingFile) {
    TempDir tempDir("StorageEngineLockFileTest_UncleanShutdownEmptyExistingFile");
    {
        std::string filename(tempDir.path() + "/mongod.lock");
        std::ofstream(filename.c_str());
    }
    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_FALSE(lockFile.createdByUncleanShutdown());
}

TEST(StorageEngineLockFileTest, UncleanShutdownNonEmptyExistingFile) {
    TempDir tempDir("StorageEngineLockFileTest_UncleanShutdownNonEmptyExistingFile");
    {
        std::string filename(tempDir.path() + "/mongod.lock");
        std::ofstream ofs(filename.c_str());
        ofs << 12345 << std::endl;
    }
    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_TRUE(lockFile.createdByUncleanShutdown());
}

TEST(StorageEngineLockFileTest, OpenInvalidDirectory) {
    StorageEngineLockFile lockFile("no_such_directory");
    ASSERT_EQUALS((boost::filesystem::path("no_such_directory") / "mongod.lock").string(),
                  lockFile.getFilespec());
    Status status = lockFile.open();
    ASSERT_NOT_OK(status);
    ASSERT_EQUALS(ErrorCodes::NonExistentPath, status.code());
}

// Cause ::open() to fail by providing a regular file instead of a directory for 'dbpath'.
TEST(StorageEngineLockFileTest, OpenInvalidFilename) {
    TempDir tempDir("StorageEngineLockFileTest_OpenInvalidFilename");
    std::string filename(tempDir.path() + "/some_file");
    std::ofstream(filename.c_str());
    StorageEngineLockFile lockFile(filename);
    Status status = lockFile.open();
    ASSERT_NOT_OK(status);
    ASSERT_EQUALS(ErrorCodes::DBPathInUse, status.code());
}

TEST(StorageEngineLockFileTest, OpenNoExistingLockFile) {
    TempDir tempDir("StorageEngineLockFileTest_OpenNoExistingLockFile");
    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_OK(lockFile.open());
    lockFile.close();
}

TEST(StorageEngineLockFileTest, OpenEmptyLockFile) {
    TempDir tempDir("StorageEngineLockFileTest_OpenEmptyLockFile");
    StorageEngineLockFile lockFile(tempDir.path());
    std::string filename(lockFile.getFilespec());
    std::ofstream(filename.c_str());
    ASSERT_OK(lockFile.open());
    lockFile.close();
}

TEST(StorageEngineLockFileTest, WritePidFileNotOpened) {
    TempDir tempDir("StorageEngineLockFileTest_WritePidFileNotOpened");
    StorageEngineLockFile lockFile(tempDir.path());
    Status status = lockFile.writePid();
    ASSERT_NOT_OK(status);
    ASSERT_EQUALS(ErrorCodes::FileNotOpen, status.code());
}

TEST(StorageEngineLockFileTest, WritePidFileOpened) {
    TempDir tempDir("StorageEngineLockFileTest_WritePidFileOpened");
    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_OK(lockFile.open());
    ASSERT_OK(lockFile.writePid());
    lockFile.close();

    // Read PID from lock file.
    std::string filename(lockFile.getFilespec());
    std::ifstream ifs(filename.c_str());
    int64_t pidFromLockFile = 0;
    ASSERT_TRUE(ifs >> pidFromLockFile);
    ASSERT_EQUALS(ProcessId::getCurrent().asInt64(), pidFromLockFile);
}

// Existing data in lock file must be removed before writing process ID.
TEST(StorageEngineLockFileTest, WritePidTruncateExistingFile) {
    TempDir tempDir("StorageEngineLockFileTest_WritePidTruncateExistingFile");
    StorageEngineLockFile lockFile(tempDir.path());
    {
        std::string filename(tempDir.path() + "/mongod.lock");
        std::ofstream ofs(filename.c_str());
        std::string currentPidStr = ProcessId::getCurrent().toString();
        ASSERT_FALSE(currentPidStr.empty());
        ofs << std::string(currentPidStr.size() * 100, 'X') << std::endl;
    }
    ASSERT_OK(lockFile.open());
    ASSERT_OK(lockFile.writePid());
    lockFile.close();

    // Read PID from lock file.
    std::string filename(lockFile.getFilespec());
    std::ifstream ifs(filename.c_str());
    int64_t pidFromLockFile = 0;
    ASSERT_TRUE(ifs >> pidFromLockFile);
    ASSERT_EQUALS(ProcessId::getCurrent().asInt64(), pidFromLockFile);

    // There should not be any data in the file after the process ID.
    std::string extraData;
    ASSERT_FALSE(ifs >> extraData);
}

TEST(StorageEngineLockFileTest, ClearPidAndUnlock) {
    TempDir tempDir("StorageEngineLockFileTest_ClearPidAndUnlock");
    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_OK(lockFile.open());
    ASSERT_OK(lockFile.writePid());

    // Clear lock file contents.
    lockFile.clearPidAndUnlock();
    ASSERT_TRUE(boost::filesystem::exists(lockFile.getFilespec()));
    ASSERT_EQUALS(0U, boost::filesystem::file_size(lockFile.getFilespec()));
}

class ScopedReadOnlyDirectory {
public:
    ScopedReadOnlyDirectory(const std::string& path) : _path(std::move(path)) {
        _applyToPathRecursive(_path, makePathReadOnly);
    }

    ~ScopedReadOnlyDirectory() {
        _applyToPathRecursive(_path, makePathWritable);
    }

private:
    const std::string& _path;

    static void makePathReadOnly(const boost::filesystem::path& path) {
#ifdef _WIN32
        ::SetFileAttributes(path.c_str(), FILE_ATTRIBUTE_READONLY);
#else
        ::chmod(path.c_str(), 0544);
#endif
    }

    static void makePathWritable(const boost::filesystem::path& path) {
#ifdef _WIN32
        ::SetFileAttributes(path.c_str(), FILE_ATTRIBUTE_NORMAL);
#else
        ::chmod(path.c_str(), 0777);
#endif
    }

    template <typename Func>
    static void _applyToPathRecursive(const boost::filesystem::path& path, Func func) {
        func(path);

        using rdi = boost::filesystem::recursive_directory_iterator;
        for (auto iter = rdi{path}; iter != rdi(); ++iter) {
            func(*iter);
        }
    }
};

#ifndef _WIN32

// Windows has no concept of read only directories - only read only files.
TEST(StorageEngineLockFileTest, ReadOnlyDirectory) {
    // If we are running as root, do not run this test as read only permissions will not be
    // respected.
    if (::getuid() == 0) {
        return;
    }

    TempDir tempDir("StorageEngineLockFileTest_ReadOnlyDirectory");

    // Make tempDir read-only.
    ScopedReadOnlyDirectory srod(tempDir.path());

    StorageEngineLockFile lockFile(tempDir.path());

    auto openStatus = lockFile.open();

    ASSERT_NOT_OK(openStatus);
    ASSERT_EQ(openStatus, ErrorCodes::IllegalOperation);
}

#endif

TEST(StorageEngineLockFileTest, ReadOnlyDirectoryWithLockFile) {
#ifndef _WIN32
    // If we are running as root, do not run this test as read only permissions will not be
    // respected.
    if (::getuid() == 0) {
        return;
    }
#endif

    TempDir tempDir("StorageEngineLockFileTest_ReadOnlyDirectoryWithLockFile");

    StorageEngineLockFile lockFile(tempDir.path());
    ASSERT_OK(lockFile.open());
    ASSERT_OK(lockFile.writePid());

    // Make tempDir read-only.
    ScopedReadOnlyDirectory srod(tempDir.path());

    // Try to create a new lock file.
    StorageEngineLockFile lockFile2(tempDir.path());

    auto openStatus = lockFile2.open();

    ASSERT_NOT_OK(openStatus);
    ASSERT_EQ(openStatus, ErrorCodes::IllegalOperation);
}

}  // namespace

max_stars_repo_name: SunguckLee/real-mongodb

max_issues_repo_name: SunguckLee/real-mongodb

max_forks_repo_name: SunguckLee/real-mongodb


text:
// ========================================================================= //
// Filename      :  test_sampling.cpp
// Creation Date :  2016-6-21
// Created by    :  anfranek
// ========================================================================= //

#include <gtest/gtest.h>

#include <cmath>

#include <Eigen/Core>

#include "sampling.h"

TEST(equidistant_sampling, two_point_line)
{
    util::AlignedVecOfVec2d line = {{0, 0}, {4, 0}};

    util::AlignedVecOfVec2d expected = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}};
    auto sampled = util::sample_equidistant(line, 5);

    EXPECT_EQ(expected, sampled);
}

TEST(equidistant_sampling, three_point_line)
{
    util::AlignedVecOfVec2d line = {{0, 0}, {1, 1}, {2, 0}};

    util::AlignedVecOfVec2d expected = {{0, 0}, {2./3., 2./3.}, {4./3., 2./3.}, {2, 0}};
    auto sampled = util::sample_equidistant(line, 4);

    for(int i = 0; i < static_cast<int>(expected.size()); i++)
    {
        EXPECT_DOUBLE_EQ(expected[i][0], sampled[i][0]);
        EXPECT_DOUBLE_EQ(expected[i][1], sampled[i][1]);
    }
}