<commit_before>#ifndef USER_THREAD_CONTEXTTRAITS_HPP
#define USER_THREAD_CONTEXTTRAITS_HPP

#include "mysetjmp.h"
#include "user-thread-debug.hpp"
#include "workqueue.hpp"
#include "stackallocators.hpp"
#include "splitstackapi.h"
#include "stack-address-tools.hpp"

#include "call_with_alt_stack_arg3.h"

#include "config.h"

namespace orks {
namespace userthread {
namespace detail {

class Worker;

using namespace stacktool;

}
}
}

namespace orks {
namespace userthread {
namespace detail {
namespace baddesign {

inline
void call_with_alt_stack_arg3(char* altstack, std::size_t altstack_size, void* func, void* arg1, void* arg2, void* arg3) __attribute__((no_split_stack));

inline
void call_with_alt_stack_arg3(char* altstack, std::size_t altstack_size, void* func, void* arg1, void* arg2, void* arg3) {
    void* stack_base = altstack + altstack_size;
#ifndef USE_SPLITSTACKS
    // stack boundary was already changed by caller.
    // debug output will make memory destorying.
    debug::printf("func %p\n", func);
#endif

    orks_private_call_with_alt_stack_arg3_impl(arg1, arg2, arg3, stack_base, func);
}

enum class ThreadState {
    running, ended, before_launch
};

class ThreadData;
using Context = ThreadData*;

class ThreadData {

#ifdef ORKS_USERTHREAD_STACK_ALLOCATOR
    using StackAllocator = ORKS_USERTHREAD_STACK_ALLOCATOR;
#else
    using StackAllocator = SimpleStackAllocator;
#endif

    using Stack = StackAllocator::Stack;

public:
    Context(*func)(void* arg, Context prev);
    void* arg;
    Stack stack_frame;
    context env;
    ThreadState state = ThreadState::before_launch;

    ThreadData* pass_on_longjmp = 0;

#ifdef USE_SPLITSTACKS
    splitstack_context splitstack_context_;
#endif

public:

    template <typename Fn>
    ThreadData(Fn fn)
        : ThreadData((Context(*)(void*, Context)) & (exec_thread_delete<Fn>),
                     (void*)(new Fn(std::move(fn)))) {
//        auto a = exec_thread_delete<Fn>;
//        int i = a;
    }

    ThreadData(Context(*func)(void* arg, Context prev), void* arg)
        : func(func)
        , arg(arg)
        , stack_frame() {

    }

    // non copyable
    ThreadData(const ThreadData&) = delete;
    ThreadData(ThreadData&&) = delete;

    // this function is public
    // this is bad
    template <typename Fn>
    static ThreadData* create(Fn fn) {
        Stack stack = StackAllocator::allocate();
        assert(stack.size != 0);
        auto th = new(stack.stack.get()) ThreadData(fn);
        th->stack_frame = std::move(stack);
        assert(th->stack_frame.size != 0);
        return th;

    }

    // this function is public
    // this is bad
    static void destroy(ThreadData& t) {
#ifdef USE_SPLITSTACKS
        __splitstack_releasecontext(t.splitstack_context_);
#endif
        Stack stack = std::move(t.stack_frame);
        t.~ThreadData();
    }

private:
    template<typename Fn>
    static Context exec_thread_delete(void* func_obj, Context t) {
        Context r = (*static_cast<Fn*>(func_obj))(t);
        delete static_cast<Fn*>(func_obj);
        return r;
    }

};

template<class Worker>
struct BadDesignContextTraitsImpl {
    using Context = ThreadData*;
    friend Worker;
//    static Work& switch_context_(Work& next) {
//
//        debug::printf("jump to Work* %p\n", &next);
//        auto& prev = switch_context_impl(next);
//
//        call_after_context_switch(prev);
//        return prev;
//
//    }

    template <typename Fn>
    static Context make_context(Fn fn) {
        return ThreadData::create(std::move(fn));
    }

    static Context switch_context(Context next_thread) {
        return &switch_context_impl(*next_thread);
    }

    static bool is_finished(Context ctx) {
        return ctx->state == ThreadState::ended;
    }

    static void destroy_context(Context ctx) {
        ThreadData::destroy((*ctx));
    }

private:
    static ThreadData& switch_context_impl(ThreadData& next_thread, ThreadData* finished_thread = nullptr) {

        ThreadData current_thread_ {nullptr, nullptr};
        ThreadData* current_thread;

        if (finished_thread == nullptr) {
            current_thread = &current_thread_;
            debug::printf("save current thread at %p\n", current_thread);

            current_thread->state = ThreadState::running;

        } else {
            current_thread = finished_thread;
            debug::printf("current thread %p is finished\n", current_thread);
        }

        ThreadData* previous_thread = 0;
        if (next_thread.state == ThreadState::before_launch) {
            debug::printf("launch user thread!\n");

            previous_thread = &context_switch_new_context(*current_thread, next_thread);

        } else if (next_thread.state == ThreadState::running) {
            debug::printf("resume user thread %p!\n", &next_thread);

            previous_thread = &context_switch(*current_thread, next_thread);

        } else {
            debug::out << "next_thread " << &next_thread << " invalid state: " << static_cast<int>(next_thread.state)
                       << "\n";
            const auto NEVER_COME_HERE = false;
            assert(NEVER_COME_HERE);

        }

        return *previous_thread;

    }

    // always_inline for no split stack
    __attribute__((always_inline))
    static ThreadData& context_switch(ThreadData& from, ThreadData& to) {

#ifdef USE_SPLITSTACKS
        __splitstack_getcontext(from.splitstack_context_);
#endif
        if (mysetjmp(from.env)) {
#ifdef USE_SPLITSTACKS
            __splitstack_setcontext(from.splitstack_context_);
#endif
            return *from.pass_on_longjmp;
        }
        to.pass_on_longjmp = &from;
        mylongjmp(to.env);

        const auto NEVER_COME_HERE = false;
        assert(NEVER_COME_HERE);

    }

    // always_inline for no split stack
    __attribute__((always_inline))
    static ThreadData& context_switch_new_context(ThreadData& from, ThreadData& new_ctx) {

#ifdef USE_SPLITSTACKS
        __splitstack_getcontext(from.splitstack_context_);
#endif
        if (mysetjmp(from.env)) {
#ifdef USE_SPLITSTACKS
            __splitstack_setcontext(from.splitstack_context_);
#endif
            return *from.pass_on_longjmp;
        }
        new_ctx.pass_on_longjmp = &from;
        assert(new_ctx.stack_frame.stack.get() != 0);
        assert(new_ctx.stack_frame.size != 0);
        char* stack_frame = new_ctx.stack_frame.stack.get();
        call_with_alt_stack_arg3(stack_frame, new_ctx.stack_frame.size, reinterpret_cast<void*>(entry_thread),
                                 &new_ctx, nullptr, nullptr);

        const auto NEVER_COME_HERE = false;
        assert(NEVER_COME_HERE);

    }

    __attribute__((no_split_stack))
    static void entry_thread(ThreadData& thread_data);

};

template<class Worker>
void BadDesignContextTraitsImpl<Worker>::entry_thread(ThreadData& thread_data) {

#ifdef USE_SPLITSTACKS
    __stack_split_initialize();

    void* bottom = thread_data.stack_frame.stack.get() + thread_data.stack_frame.size;
    void* split_stacks_boundary = __morestack_get_guard();

    debug::printf("stack top of new thread: %p, stack size of new thread: 0x%lx\n", thread_data.stack_frame.stack.get(),
                  static_cast<unsigned long>(thread_data.stack_frame.size));
    debug::printf("stack bottom of new thread: %p, stack boundary of new thread: %p\n", bottom, split_stacks_boundary);
    assert(more_forward_than(split_stacks_boundary, bottom));
#endif

    debug::printf("start thread in new stack frame\n");
    debug::out << std::endl;

    thread_data.state = ThreadState::running;

    Context next = thread_data.func(thread_data.arg, thread_data.pass_on_longjmp);

    debug::printf("end thread\n");
    thread_data.state = ThreadState::ended;
    debug::printf("end: %p\n", &thread_data);

    switch_context_impl(*next, &thread_data);
    // no return
    // this thread context will be deleted by next thread
}

}
}
}
}

namespace orks {
namespace userthread {
namespace detail {

using BadDesignContextTraits = baddesign::BadDesignContextTraitsImpl<Worker>;

}
}
}
#endif //USER_THREAD_CONTEXTTRAITS_HPP
<commit_msg>Add data transfer feature<commit_after>#ifndef USER_THREAD_CONTEXTTRAITS_HPP
#define USER_THREAD_CONTEXTTRAITS_HPP

#include "mysetjmp.h"
#include "user-thread-debug.hpp"
#include "workqueue.hpp"
#include "stackallocators.hpp"
#include "splitstackapi.h"
#include "stack-address-tools.hpp"

#include "call_with_alt_stack_arg3.h"

#include "config.h"

namespace orks {
namespace userthread {
namespace detail {

class Worker;

using namespace stacktool;

}
}
}

namespace orks {
namespace userthread {
namespace detail {
namespace baddesign {

inline
void call_with_alt_stack_arg3(char* altstack, std::size_t altstack_size, void* func, void* arg1, void* arg2, void* arg3) __attribute__((no_split_stack));

inline
void call_with_alt_stack_arg3(char* altstack, std::size_t altstack_size, void* func, void* arg1, void* arg2, void* arg3) {
    void* stack_base = altstack + altstack_size;
#ifndef USE_SPLITSTACKS
    // stack boundary was already changed by caller.
    // debug output will make memory destorying.
    debug::printf("func %p\n", func);
#endif

    orks_private_call_with_alt_stack_arg3_impl(arg1, arg2, arg3, stack_base, func);
}

enum class ThreadState {
    running, ended, before_launch
};

class ThreadData;
using Context = ThreadData*;

class ThreadData {

#ifdef ORKS_USERTHREAD_STACK_ALLOCATOR
    using StackAllocator = ORKS_USERTHREAD_STACK_ALLOCATOR;
#else
    using StackAllocator = SimpleStackAllocator;
#endif

    using Stack = StackAllocator::Stack;

public:
    Context(*func)(void* arg, Context prev);
    void* arg;
    Stack stack_frame;
    context env;
    ThreadState state = ThreadState::before_launch;

    ThreadData* pass_on_longjmp = 0;
    void* transferred_data = nullptr;

#ifdef USE_SPLITSTACKS
    splitstack_context splitstack_context_;
#endif

public:

    template <typename Fn>
    ThreadData(Fn fn)
        : ThreadData((Context(*)(void*, Context)) & (exec_thread_delete<Fn>),
                     (void*)(new Fn(std::move(fn)))) {
//        auto a = exec_thread_delete<Fn>;
//        int i = a;
    }

    ThreadData(Context(*func)(void* arg, Context prev), void* arg)
        : func(func)
        , arg(arg)
        , stack_frame() {

    }

    // non copyable
    ThreadData(const ThreadData&) = delete;
    ThreadData(ThreadData&&) = delete;

    // this function is public
    // this is bad
    template <typename Fn>
    static ThreadData* create(Fn fn) {
        Stack stack = StackAllocator::allocate();
        assert(stack.size != 0);
        auto th = new(stack.stack.get()) ThreadData(fn);
        th->stack_frame = std::move(stack);
        assert(th->stack_frame.size != 0);
        return th;

    }

    // this function is public
    // this is bad
    static void destroy(ThreadData& t) {
#ifdef USE_SPLITSTACKS
        __splitstack_releasecontext(t.splitstack_context_);
#endif
        Stack stack = std::move(t.stack_frame);
        t.~ThreadData();
    }

private:
    template<typename Fn>
    static Context exec_thread_delete(void* func_obj, Context t) {
        Context r = (*static_cast<Fn*>(func_obj))(t);
        delete static_cast<Fn*>(func_obj);
        return r;
    }

};

template<class Worker>
struct BadDesignContextTraitsImpl {
    using Context = ThreadData*;

    template <typename Fn>
    static Context make_context(Fn fn) {
        return ThreadData::create(std::move(fn));
    }

    static Context switch_context(Context next_thread, void* transfer_data = nullptr) {
        return &switch_context_impl(*next_thread, transfer_data);
    }

    static bool is_finished(Context ctx) {
        return ctx->state == ThreadState::ended;
    }

    static void destroy_context(Context ctx) {
        ThreadData::destroy((*ctx));
    }

    void* get_transferred_data(Context ctx) {
        return ctx->transferred_data;
    }

private:
    static ThreadData& switch_context_impl(ThreadData& next_thread,
                                           void* transfer_data = nullptr,
                                           ThreadData* finished_thread = nullptr) {

        ThreadData current_thread_ {nullptr, nullptr};
        ThreadData* current_thread;

        if (finished_thread == nullptr) {
            current_thread = &current_thread_;
            debug::printf("save current thread at %p\n", current_thread);

            current_thread->state = ThreadState::running;

        } else {
            current_thread = finished_thread;
            debug::printf("current thread %p is finished\n", current_thread);
        }

        ThreadData* previous_thread = 0;
        next_thread.transferred_data = transfer_data;
        if (next_thread.state == ThreadState::before_launch) {
            debug::printf("launch user thread!\n");

            previous_thread = &context_switch_new_context(*current_thread, next_thread);

        } else if (next_thread.state == ThreadState::running) {
            debug::printf("resume user thread %p!\n", &next_thread);

            previous_thread = &context_switch(*current_thread, next_thread);

        } else {
            debug::out << "next_thread " << &next_thread << " invalid state: " << static_cast<int>(next_thread.state)
                       << "\n";
            const auto NEVER_COME_HERE = false;
            assert(NEVER_COME_HERE);

        }

        return *previous_thread;

    }

    // always_inline for no split stack
    __attribute__((always_inline))
    static ThreadData& context_switch(ThreadData& from, ThreadData& to) {

#ifdef USE_SPLITSTACKS
        __splitstack_getcontext(from.splitstack_context_);
#endif
        if (mysetjmp(from.env)) {
#ifdef USE_SPLITSTACKS
            __splitstack_setcontext(from.splitstack_context_);
#endif
            return *from.pass_on_longjmp;
        }
        to.pass_on_longjmp = &from;
        mylongjmp(to.env);

        const auto NEVER_COME_HERE = false;
        assert(NEVER_COME_HERE);

    }

    // always_inline for no split stack
    __attribute__((always_inline))
    static ThreadData& context_switch_new_context(ThreadData& from, ThreadData& new_ctx) {

#ifdef USE_SPLITSTACKS
        __splitstack_getcontext(from.splitstack_context_);
#endif
        if (mysetjmp(from.env)) {
#ifdef USE_SPLITSTACKS
            __splitstack_setcontext(from.splitstack_context_);
#endif
            return *from.pass_on_longjmp;
        }
        new_ctx.pass_on_longjmp = &from;
        assert(new_ctx.stack_frame.stack.get() != 0);
        assert(new_ctx.stack_frame.size != 0);
        char* stack_frame = new_ctx.stack_frame.stack.get();
        call_with_alt_stack_arg3(stack_frame, new_ctx.stack_frame.size, reinterpret_cast<void*>(entry_thread),
                                 &new_ctx, nullptr, nullptr);

        const auto NEVER_COME_HERE = false;
        assert(NEVER_COME_HERE);

    }

    __attribute__((no_split_stack))
    static void entry_thread(ThreadData& thread_data);

};

template<class Worker>
void BadDesignContextTraitsImpl<Worker>::entry_thread(ThreadData& thread_data) {

#ifdef USE_SPLITSTACKS
    __stack_split_initialize();

    void* bottom = thread_data.stack_frame.stack.get() + thread_data.stack_frame.size;
    void* split_stacks_boundary = __morestack_get_guard();

    debug::printf("stack top of new thread: %p, stack size of new thread: 0x%lx\n", thread_data.stack_frame.stack.get(),
                  static_cast<unsigned long>(thread_data.stack_frame.size));
    debug::printf("stack bottom of new thread: %p, stack boundary of new thread: %p\n", bottom, split_stacks_boundary);
    assert(more_forward_than(split_stacks_boundary, bottom));
#endif

    debug::printf("start thread in new stack frame\n");
    debug::out << std::endl;

    thread_data.state = ThreadState::running;

    Context next = thread_data.func(thread_data.arg, thread_data.pass_on_longjmp);

    debug::printf("end thread\n");
    thread_data.state = ThreadState::ended;
    debug::printf("end: %p\n", &thread_data);

    switch_context_impl(*next, thread_data.transferred_data, &thread_data);
    // no return
    // this thread context will be deleted by next thread
}

}
}
}
}

namespace orks {
namespace userthread {
namespace detail {

using BadDesignContextTraits = baddesign::BadDesignContextTraitsImpl<Worker>;

}
}
}
#endif //USER_THREAD_CONTEXTTRAITS_HPP
<|endoftext|>


<commit_before>#ifndef PYTHONIC_INCLUDE_NUMPY_RINT_HPP
#define PYTHONIC_INCLUDE_NUMPY_RINT_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"

PYTHONIC_NS_BEGIN

namespace numpy
{
  namespace wrapper
  {
    template <class T>
    T rint(T const &v);
  }
#define NUMPY_NARY_FUNC_NAME rint
#define NUMPY_NARY_FUNC_SYM wrapper::rint
#include "pythonic/include/types/numpy_nary_expr.hpp"
}
PYTHONIC_NS_END

#endif
<commit_msg>Add missing rint declaration<commit_after>#ifndef PYTHONIC_INCLUDE_NUMPY_RINT_HPP
#define PYTHONIC_INCLUDE_NUMPY_RINT_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"

PYTHONIC_NS_BEGIN

namespace numpy
{
  namespace wrapper
  {
    template <class T>
    T rint(T const &v);
    template <class T>
    std::complex<T> rint(std::complex<T> const &v);
  }
#define NUMPY_NARY_FUNC_NAME rint
#define NUMPY_NARY_FUNC_SYM wrapper::rint
#include "pythonic/include/types/numpy_nary_expr.hpp"
}
PYTHONIC_NS_END

#endif
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <vector>
#include <tuple>
#include <functional>

#include <iod/tags.hh>
#include <iod/grammar.hh>

namespace iod
{
  template <typename ...T>
  struct sio;

  template <typename T, typename ...Tail>
  inline std::vector<T> iod_array(const T& t, Tail... args);

  namespace iod_internals
  {

    // Fill an array from a variable list of arguments.
    template <typename T>
    inline void array_fill(std::vector<T>&)
    {
    }

    template <typename T, typename ...Tail>
    inline void array_fill(const T& a, const Tail&... args, std::vector<T>& array)
    {
      array.push_back(a);
      array_fill(args..., array);
    }

    // Assign the attributes of src to the attributes of dst.
    template <int N, typename D, typename S>
    struct iod_assign
    {
      static inline void run(D& dst, const S& src)
        {
          const auto& src_attr = src.template get_nth<N>();

          typedef typename S::template _nth_attribute<N>::symbol_type symbol_type;
          dst.template get<symbol_type>() = src_attr.value();
          iod_assign<N-1, D, S>::run(dst, src);
        }
    };
    template <typename D, typename S>
    struct iod_assign<-1, D, S>
    {
      static inline void run(D&, const S&)
      {
      }
    };

  }

  template <template <class> class Const,
            int N, typename F, typename... T>
  struct iod_foreach_runner
  {
    static inline void run(F f, Const<T>&... args)
    {
      iod_foreach_runner<Const, N-1, F, T...>::run(f, args...);
      f(args.template get_nth_attribute<N>()...);
    }
  };

  template <template <class> class Const,
            typename F, typename... T>
  struct iod_foreach_runner<Const, -1, F, T...>
  {
    static inline void run(F, Const<T>&...)
    {
    }
  };

  // Apply a function on all member of the iod objects \args.
  template <typename F, typename T, typename ...U>
  void foreach_attribute(F f, T& arg, U&... tail)
  {
    iod_foreach_runner<std::remove_const_t, T::_size - 1, F, T, U...>::run(f, arg, tail...);
  }

  template <typename F, typename T, typename ...U>
  void foreach_attribute(F f, const T& arg, const U&... tail)
  {
    iod_foreach_runner<std::add_const_t, T::_size - 1, F, T, U...>::run(f, arg, tail...);
  }

  // Apply a function on all member of the iod objects \args.
  template <typename F, typename T, typename ...U>
  void foreach_attribute_value(F f, T& arg, U&... tail)
  {
    auto g = [&f] (auto& m) { return f(m.value()); };
    iod_foreach_runner<std::remove_const_t, T::_size - 1, decltype(g), T, U...>::run(g, arg, tail...);
  }

  template <typename F, typename T, typename ...U>
  void foreach_attribute_value(F f, const T& arg, const U&... tail)
  {
    auto g = [&f] (auto& m) { return f(m.value()); };
    iod_foreach_runner<std::add_const_t, T::_size - 1, decltype(g), T, U...>::run(g, arg, tail...);
  }

  struct attribute_not_found
  {
    typedef not_found symbol_type;
    typedef int value_type;
    const int& value() const { return x; }
    int& value() { return x; }

    int x;
  };

  template <>
  struct sio<>
  {
    enum { _size = 0, _empty = true };

    template <typename E>
    struct _has { static const bool value = false; };

    constexpr sio() { }
    constexpr static int size() { return _size; }
    constexpr static bool empty() { return true; }
    template <typename T>
    constexpr static bool has(T) { return false; }
    template <unsigned N>
    not_found get_nth() const { return not_found(); }
    template <unsigned N>
    const attribute_not_found& get_nth_attribute() const { return *(attribute_not_found*)(0); }
    template <unsigned N>
    attribute_not_found& get_nth_attribute() { return *(attribute_not_found*)(0); }
    template <typename E, typename D>
    D get(const E&, const D default_) const { return default_; }

    auto symbols_as_tuple() const { return std::make_tuple(); }
  };

  template <typename T, typename ...Tail>
  struct sio<T, Tail...> : public T, public sio<Tail...>
  {
    typedef sio<T, Tail...> self;
    typedef sio<Tail...> super;
    typedef std::tuple<T, Tail...> tuple_type;

    enum { _size = 1 + sizeof...(Tail), _empty = 0 };

    template <unsigned N, typename U, typename P = void>
    struct _nth_attribute_ {};

    template <unsigned N, typename U>
    struct _nth_attribute_<N, U, std::enable_if_t<(N < _size)>>
    { typedef typename std::tuple_element<N, U>::type type; };

    template <unsigned N, typename U>
    struct _nth_attribute_<N, U, std::enable_if_t<(N >= _size)>>
    { typedef attribute_not_found type; };

    template <unsigned N>
    using _nth_attribute = typename _nth_attribute_<N, std::tuple<T, Tail...>>::type;

    // -----------------------------------------
    // Retrive type of attribute with symbol S.
    // -----------------------------------------
    template <unsigned N, typename C, typename S>
    struct _attribute_;

    template <typename C, typename S>
    struct _attribute_<_size, C, S>
    {
      typedef attribute_not_found type;
    };

    template <unsigned N, typename S>
    struct _attribute_<N, S, S>
    {
      typedef _nth_attribute<N> type;
    };

    template <unsigned N, typename C, typename S>
    struct _attribute_
    {
      typedef typename _attribute_<N+1, typename _nth_attribute<N+1>::symbol_type, S>::type type;
    };

    template <typename S>
    using _attribute = typename _attribute_<0, typename _nth_attribute<0>::symbol_type, S>::type;

    template <typename S>
    using attribute_value_type = typename _attribute_<0, typename _nth_attribute<0>::symbol_type, S>::type::value_type;

    template <int V>
    struct simple_enum { enum { value = V}; };

    template <typename E>
    using _has = simple_enum<not std::is_same<_attribute<E>, attribute_not_found>::value>;

    // Constructor.
    inline sio() = default;

    inline sio(const T&& attr, const Tail&&... tail)
      : T(attr),
        sio<Tail...>(std::forward<const Tail>(tail)...)
      {
      }

    inline sio(const T& attr, const Tail&... tail)
      : T(attr),
        sio<Tail...>(std::forward<const Tail>(tail)...)
      {
      }

    // Get the attribute associated with the symbol S.
    template <typename S>
    auto& symbol_to_attribute(S = S())
    {
      return *static_cast<_attribute<S>*>(this);
    }

    template <typename S>
    const auto& symbol_to_attribute(S = S()) const
    {
      return *static_cast<const _attribute<S>*>(this);
    }

    // Access to a member from a symbol.
    template <typename E>
    auto& operator[](const E&)
    {
      return symbol_to_attribute<typename E::symbol_type>().value();
    }

    template <typename E>
    const auto& operator[](const E&) const
    {
      return symbol_to_attribute<E>().value();
    }

    template <typename E, typename D>
    decltype(auto)
    get(const E& e, const D, std::enable_if_t<_has<E>::value>* = 0) const
    {
      return (*this)[e];
    }

    template <typename E, typename D>
    typename std::enable_if<not _has<E>::value, D>::type
    get(const E&, D default_) const
    {
      return default_;
    }

    // Check if the object has this symbol.
    template <typename E>
    constexpr static bool has(const E&)
    {
      return _has<E>::value;
    }

    // Check if the object has this symbol.
    constexpr static int size()
    {
      return _size;
    }

    constexpr static bool empty()
    {
      return _size == 0;
    }

    // Access to the super attribute.
    super& get_super() { return *this; }
    const super& get_super() const { return *this; }

    // Get the nth attribute.
    template <unsigned N>
    typename std::enable_if<N!=0, _nth_attribute<N>&>::type
    get_nth_attribute() { return get_super().template get_nth_attribute<N-1>(); }

    template <unsigned N>
    typename std::enable_if<N==0, _nth_attribute<N>&>::type
    get_nth_attribute() { return *static_cast<T*> (this); }

    template <unsigned N>
    typename std::enable_if<N!=0, const _nth_attribute<N>&>::type
    get_nth_attribute() const { return get_super().template get_nth_attribute<N-1>(); }

    template <unsigned N>
    typename std::enable_if<N==0, const _nth_attribute<N>&>::type
    get_nth_attribute() const { return *static_cast<const T*> (this); }

    template <unsigned N>
    const typename _nth_attribute<N>::value_type&
    get_nth() const { return get_nth_attribute<N>().value(); }

    template <unsigned N>
    typename _nth_attribute<N>::value_type&
    get_nth() { return get_nth_attribute<N>().value(); }

    auto&& values_as_tuple() { return std::forward_as_tuple(static_cast<T*>(this)->value(),
                                                            static_cast<Tail*>(this)->value()...); }
    auto&& values_as_tuple() const { return std::forward_as_tuple(static_cast<const T*>(this)->value(),
                                                                  static_cast<const Tail*>(this)->value()...); }

    auto symbols_as_tuple() const { return std::make_tuple(static_cast<const T*>(this)->symbol(),
                                                           static_cast<const Tail*>(this)->symbol()...); }

    // Assignment.
    template <typename O, typename... Otail>
    self& operator=(const sio<O, Otail...>& o)
    {
      foreach(o) | [this] (auto& m) { (*this)[m.symbol()] = m.value(); };
      return *this;
    }

  };

  template <typename R, typename S>
  using has_symbol = typename R::template _has<S>;

} // end of namespace iod.

#include <iod/symbol.hh>
#include <iod/sio_utils.hh>
<commit_msg>Cleanup sio operator=<commit_after>#pragma once

#include <string>
#include <vector>
#include <tuple>
#include <functional>

#include <iod/tags.hh>
#include <iod/grammar.hh>

namespace iod
{
  template <typename ...T>
  struct sio;

  template <typename T, typename ...Tail>
  inline std::vector<T> iod_array(const T& t, Tail... args);

  namespace iod_internals
  {

    // Fill an array from a variable list of arguments.
    template <typename T>
    inline void array_fill(std::vector<T>&)
    {
    }

    template <typename T, typename ...Tail>
    inline void array_fill(const T& a, const Tail&... args, std::vector<T>& array)
    {
      array.push_back(a);
      array_fill(args..., array);
    }

    // Assign the attributes of src to the attributes of dst.
    template <int N, typename D, typename S>
    struct iod_assign
    {
      static inline void run(D& dst, const S& src)
        {
          const auto& src_attr = src.template get_nth<N>();

          typedef typename S::template _nth_attribute<N>::symbol_type symbol_type;
          dst.template get<symbol_type>() = src_attr.value();
          iod_assign<N-1, D, S>::run(dst, src);
        }
    };
    template <typename D, typename S>
    struct iod_assign<-1, D, S>
    {
      static inline void run(D&, const S&)
      {
      }
    };

  }

  template <template <class> class Const,
            int N, typename F, typename... T>
  struct iod_foreach_runner
  {
    static inline void run(F f, Const<T>&... args)
    {
      iod_foreach_runner<Const, N-1, F, T...>::run(f, args...);
      f(args.template get_nth_attribute<N>()...);
    }
  };

  template <template <class> class Const,
            typename F, typename... T>
  struct iod_foreach_runner<Const, -1, F, T...>
  {
    static inline void run(F, Const<T>&...)
    {
    }
  };

  // Apply a function on all member of the iod objects \args.
  template <typename F, typename T, typename ...U>
  void foreach_attribute(F f, T& arg, U&... tail)
  {
    iod_foreach_runner<std::remove_const_t, T::_size - 1, F, T, U...>::run(f, arg, tail...);
  }

  template <typename F, typename T, typename ...U>
  void foreach_attribute(F f, const T& arg, const U&... tail)
  {
    iod_foreach_runner<std::add_const_t, T::_size - 1, F, T, U...>::run(f, arg, tail...);
  }

  // Apply a function on all member of the iod objects \args.
  template <typename F, typename T, typename ...U>
  void foreach_attribute_value(F f, T& arg, U&... tail)
  {
    auto g = [&f] (auto& m) { return f(m.value()); };
    iod_foreach_runner<std::remove_const_t, T::_size - 1, decltype(g), T, U...>::run(g, arg, tail...);
  }

  template <typename F, typename T, typename ...U>
  void foreach_attribute_value(F f, const T& arg, const U&... tail)
  {
    auto g = [&f] (auto& m) { return f(m.value()); };
    iod_foreach_runner<std::add_const_t, T::_size - 1, decltype(g), T, U...>::run(g, arg, tail...);
  }

  struct attribute_not_found
  {
    typedef not_found symbol_type;
    typedef int value_type;
    const int& value() const { return x; }
    int& value() { return x; }

    int x;
  };

  template <>
  struct sio<>
  {
    enum { _size = 0, _empty = true };

    template <typename E>
    struct _has { static const bool value = false; };

    constexpr sio() { }
    constexpr static int size() { return _size; }
    constexpr static bool empty() { return true; }
    template <typename T>
    constexpr static bool has(T) { return false; }
    template <unsigned N>
    not_found get_nth() const { return not_found(); }
    template <unsigned N>
    const attribute_not_found& get_nth_attribute() const { return *(attribute_not_found*)(0); }
    template <unsigned N>
    attribute_not_found& get_nth_attribute() { return *(attribute_not_found*)(0); }
    template <typename E, typename D>
    D get(const E&, const D default_) const { return default_; }

    auto symbols_as_tuple() const { return std::make_tuple(); }
  };

  template <typename T, typename ...Tail>
  struct sio<T, Tail...> : public T, public sio<Tail...>
  {
    typedef sio<T, Tail...> self;
    typedef sio<Tail...> super;
    typedef std::tuple<T, Tail...> tuple_type;

    enum { _size = 1 + sizeof...(Tail), _empty = 0 };

    template <unsigned N, typename U, typename P = void>
    struct _nth_attribute_ {};

    template <unsigned N, typename U>
    struct _nth_attribute_<N, U, std::enable_if_t<(N < _size)>>
    { typedef typename std::tuple_element<N, U>::type type; };

    template <unsigned N, typename U>
    struct _nth_attribute_<N, U, std::enable_if_t<(N >= _size)>>
    { typedef attribute_not_found type; };

    template <unsigned N>
    using _nth_attribute = typename _nth_attribute_<N, std::tuple<T, Tail...>>::type;

    // -----------------------------------------
    // Retrive type of attribute with symbol S.
    // -----------------------------------------
    template <unsigned N, typename C, typename S>
    struct _attribute_;

    template <typename C, typename S>
    struct _attribute_<_size, C, S>
    {
      typedef attribute_not_found type;
    };

    template <unsigned N, typename S>
    struct _attribute_<N, S, S>
    {
      typedef _nth_attribute<N> type;
    };

    template <unsigned N, typename C, typename S>
    struct _attribute_
    {
      typedef typename _attribute_<N+1, typename _nth_attribute<N+1>::symbol_type, S>::type type;
    };

    template <typename S>
    using _attribute = typename _attribute_<0, typename _nth_attribute<0>::symbol_type, S>::type;

    template <typename S>
    using attribute_value_type = typename _attribute_<0, typename _nth_attribute<0>::symbol_type, S>::type::value_type;

    template <int V>
    struct simple_enum { enum { value = V}; };

    template <typename E>
    using _has = simple_enum<not std::is_same<_attribute<E>, attribute_not_found>::value>;

    // Constructor.
    inline sio() = default;

    inline sio(const T&& attr, const Tail&&... tail)
      : T(attr),
        sio<Tail...>(std::forward<const Tail>(tail)...)
      {
      }

    inline sio(const T& attr, const Tail&... tail)
      : T(attr),
        sio<Tail...>(std::forward<const Tail>(tail)...)
      {
      }

    // Get the attribute associated with the symbol S.
    template <typename S>
    auto& symbol_to_attribute(S = S())
    {
      return *static_cast<_attribute<S>*>(this);
    }

    template <typename S>
    const auto& symbol_to_attribute(S = S()) const
    {
      return *static_cast<const _attribute<S>*>(this);
    }

    // Access to a member from a symbol.
    template <typename E>
    auto& operator[](const E&)
    {
      return symbol_to_attribute<typename E::symbol_type>().value();
    }

    template <typename E>
    const auto& operator[](const E&) const
    {
      return symbol_to_attribute<E>().value();
    }

    template <typename E, typename D>
    decltype(auto)
    get(const E& e, const D, std::enable_if_t<_has<E>::value>* = 0) const
    {
      return (*this)[e];
    }

    template <typename E, typename D>
    typename std::enable_if<not _has<E>::value, D>::type
    get(const E&, D default_) const
    {
      return default_;
    }

    // Check if the object has this symbol.
    template <typename E>
    constexpr static bool has(const E&)
    {
      return _has<E>::value;
    }

    // Check if the object has this symbol.
    constexpr static int size()
    {
      return _size;
    }

    constexpr static bool empty()
    {
      return _size == 0;
    }

    // Access to the super attribute.
    super& get_super() { return *this; }
    const super& get_super() const { return *this; }

    // Get the nth attribute.
    template <unsigned N>
    typename std::enable_if<N!=0, _nth_attribute<N>&>::type
    get_nth_attribute() { return get_super().template get_nth_attribute<N-1>(); }

    template <unsigned N>
    typename std::enable_if<N==0, _nth_attribute<N>&>::type
    get_nth_attribute() { return *static_cast<T*> (this); }

    template <unsigned N>
    typename std::enable_if<N!=0, const _nth_attribute<N>&>::type
    get_nth_attribute() const { return get_super().template get_nth_attribute<N-1>(); }

    template <unsigned N>
    typename std::enable_if<N==0, const _nth_attribute<N>&>::type
    get_nth_attribute() const { return *static_cast<const T*> (this); }

    template <unsigned N>
    const typename _nth_attribute<N>::value_type&
    get_nth() const { return get_nth_attribute<N>().value(); }

    template <unsigned N>
    typename _nth_attribute<N>::value_type&
    get_nth() { return get_nth_attribute<N>().value(); }

    auto&& values_as_tuple() { return std::forward_as_tuple(static_cast<T*>(this)->value(),
                                                            static_cast<Tail*>(this)->value()...); }
    auto&& values_as_tuple() const { return std::forward_as_tuple(static_cast<const T*>(this)->value(),
                                                                  static_cast<const Tail*>(this)->value()...); }

    auto symbols_as_tuple() const { return std::make_tuple(static_cast<const T*>(this)->symbol(),
                                                           static_cast<const Tail*>(this)->symbol()...); }

    // Assignment.
    template <typename... Otail>
    self& operator=(const sio<Otail...>& o)
    {
      foreach(o) | [this] (auto& m) { (*this)[m.symbol()] = m.value(); };
      return *this;
    }

  };

  template <typename R, typename S>
  using has_symbol = typename R::template _has<S>;

} // end of namespace iod.

#include <iod/symbol.hh>
#include <iod/sio_utils.hh>
<|endoftext|>


<commit_before>#pragma once

#include <initializer_list>
#include "Print-lite.hpp"
#include <algorithm>
#include <stdexcept>
#include <iterator>
#include <memory>
#include <string>
#include <random>

namespace evt {

	template <typename Type>
	class Array {

		// MARK: - Attributes

		std::unique_ptr<Type[]> values { nullptr };
		size_t count_ { 0 };
		size_t capacity_ { 0 };

		// MARK: - Private functions

		template <typename Container>
		void assignNewElements(const Container& elements) {
			count_ = std::distance(std::begin(elements), std::end(elements));
			capacity_ = count_;

			#if __cplusplus >= 201400
				values = std::make_unique<Type[]>(count());
			#elif __cplusplus >= 201100
				values = std::unique_ptr<Type[]>(new Type[count()]);
			#endif

			size_t index = 0;
			for (const auto& element: elements) {
				values[index] = element;
				++index;
			}
		}

		template <typename Container>
		Array& appendNewElements(const Container& newElements) {

			size_t countOfContainer = std::distance(std::begin(newElements), std::end(newElements));

			if (capacity() >= (count() + countOfContainer)) {

				size_t index = count();
				for (const auto& newElement: newElements) {
					values[index] = newElement;
					++index;
				}

				count_ += countOfContainer;
			}
			else {

				size_t newCount = (this->isEmpty()) ? (countOfContainer) : (count() * 2);

				while (newCount < (count() + countOfContainer)) {
					newCount += 2;
				}

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(newCount);
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues (new Type[newCount]);
				#endif

				if (count() > 0) {
					std::copy(this->begin(), this->end(), &newValues[0]);
				}

				size_t index = count();
				for (const auto& element: newElements) {
					newValues[index] = element;
					++index;
				}

				values = move(newValues);

				capacity_ = newCount;
				count_ = count() + countOfContainer;
			}

			return *this;
		}

		// TRUE if elements are the same
		template<typename Container>
		bool compareElements(const Container& elements) const {

			size_t index = 0;
			for (const auto& element: elements) {
				if (values[index] != element) {
					return false;
				}
				++index;
			}

			return true;
		}

		void checkIfEmpty() const {
			if (count() == 0) {
				throw std::length_error("Array is empty (lenght == 0)");
			}
		}

		void checkIfOutOfRange(const size_t index) const {
			if (index >= count()) {
				throw std::out_of_range("Index out of range");
			}
		}

	public:

		// MARK: Constructors

		Array() {}
		template<typename Container>
		Array(const Container& elements) { assignNewElements(elements); }
		Array(const std::initializer_list<Type>& elements) { assignNewElements(elements); }
		explicit Array(const Array& otherArray) { (*this) = otherArray; }

		explicit Array(const int32_t capacity): capacity_(capacity) { // Type can't be size_t because it intefere with the other constructor

			size_t intialCapacity = (capacity < 0) ? (- capacity) : (capacity);

			#if __cplusplus >= 201400
				values = std::make_unique<Type[]>(intialCapacity);
			#elif __cplusplus >= 201100
				values = std::unique_ptr<Type[]>(new Type[intialCapacity]);
			#endif
		}

		size_t count() const { return count_; }
		size_t capacity() const { return capacity_; }

		// MARK: Manage elements

		void insert(const Type& newElement, const size_t index) {

			checkIfOutOfRange(index);

			std::unique_ptr<Type[]> newValues = nullptr;

			if (capacity() == count()) {

				size_t newCount = (this->isEmpty()) ? (2) : (count() * 2);

				#if __cplusplus >= 201400
					newValues = std::make_unique<Type[]>(newCount);
				#elif __cplusplus >= 201100
					newValues = std::unique_ptr<Type[]>(new Type[newCount]);
				#endif

				std::copy(this->begin(), this->end(), &newValues[0]);
				std::copy(&newValues[index], &newValues[count_ + 1], &newValues[index + 1]);

				capacity_ = newCount;
			}
			else {

				#if __cplusplus >= 201400
					newValues = std::make_unique<Type[]>(count());
				#elif __cplusplus >= 201100
					newValues = std::unique_ptr<Type[]>(new Type[count()]);
				#endif

				std::copy(this->begin(), this->end(), &newValues[0]);
				std::copy(&newValues[index], &newValues[count()], &newValues[index + 1]);
			}

			newValues[index] = newElement;

			values = move(newValues);

			count_ += 1;
		}

		void append(const Type& newElement) {

			if (capacity() == count()) {

				size_t newCount = (this->isEmpty()) ? (2) : (count() * 2);

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(newCount);
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues (new Type[newCount]);
				#endif

				if (count() > 0) {
					std::copy(this->begin(), this->end(), &newValues[0]);
				}

				newValues[count()] = newElement;

				values = move(newValues);

				capacity_ = newCount;
			}
			else if (count() < capacity()) {
				values[count()] = newElement;
			}

			count_ += 1;
		}

		template<typename Container>
		void appendElements(const Container& newElements) { (*this) += newElements; }
		void append(const std::initializer_list<Type>& newElements) { (*this) += newElements; }

		void resize(const size_t newSize) {

			if (newSize == 0 && count() > 0 && capacity() > 0 && values != nullptr) {
				removeAll();
			}

			checkIfEmpty();

			if (newSize < capacity()) {
				std::for_each(&values[newSize], this->end(), [](Type& value){ value = Type{}; });
				count_ = newSize;
			}
			else if (newSize > capacity()) {

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(newSize);
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues(new Type[newSize]);
				#endif

				std::copy(this->begin(), this->end(), &newValues[0]);

				values = move(newValues);
				capacity_ = newSize;
			}
		}

		bool shrink() {

			if (capacity() > count()) {

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(count());
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues (new Type[count()]);
				#endif

				if (count() > 0) {
					std::copy(this->begin(), this->end(), &newValues[0]);
				}

				values = move(newValues);

				capacity_ = count();

				return true;
			}

			return false;
		}

		void clear() {
			removeAll(true);
		}

		void removeAll(const bool keepCapacity = false) {

			if (keepCapacity) {
				if (values != nullptr) {
					std::for_each(this->begin(), this->end(), [](Type& value){ value = Type{}; });
					count_ = 0;
				}
			}
			else {

				#if __cplusplus >= 201400
					values = std::make_unique<Type[]>(0);
				#elif __cplusplus >= 201100
					values = std::unique_ptr<Type[]>(new Type[0]);
				#endif

				count_ = 0;
				capacity_ = 0;
			}
		}

		void removeAt(const size_t index, const bool shrinkIfEmpty = true) {

			if (count() == 1 && capacity() > 1 && values != nullptr && shrinkIfEmpty) {
				shrink();
			}

			checkIfEmpty();
			checkIfOutOfRange(index);

			std::copy(&values[index + 1], this->end(), &values[index]);
			values[count() - 1] = Type{};

			count_ -= 1;
		}

		void removeLast(const bool shrinkIfEmpty = true) {

			if (count() == 1 && capacity() > 1 && values != nullptr && shrinkIfEmpty) {
				shrink();
			}

			checkIfEmpty();

			values[count()] = Type{};
			count_ -= 1;
		}

		void removeFirst() {
			removeAt(0);
		}

		bool contains(const Type& element) const {
			checkIfEmpty();
			return (std::find(this->begin(), this->end(), element)) != this->end();
		}

		bool isEmpty() const {
			return (count() == 0);
		}

		std::string toString() const {

			if (this->isEmpty()) {
				return "[]";
			}

			std::string output = "[";

			size_t position = 0;
			for (const auto& value: *this) {
				output += quotedString(value);

				if (position+1 < count()) {
					output += ", ";
				}

				++position;
			}

			output += "]";

			return output;
		}

		// MARK: Operators overload

		Type& operator[](const size_t index) {
			checkIfOutOfRange(index);
			return values[index];
		}

		template<typename Container>
		Array& operator+=(const Container& newElements) {
			return appendNewElements(newElements);
		}

		Array& operator+=(const std::initializer_list<Type>& newElements) {
			return appendNewElements(newElements);
		}

		template<typename Container>
		bool operator==(const Container& elements) const {
			return compareElements(elements);
		}

		bool operator==(const std::initializer_list<Type>& elements) const {
			return compareElements(elements);
		}

		template<typename Container>
		bool operator!=(const Container& elements) const {
			return !( (*this) == elements );
		}

		bool operator!=(const std::initializer_list<Type>& elements) const {
			return !( (*this) == elements );
		}

		Array& operator=(const Array& otherArray) {

			count_ = otherArray.count();
			capacity_ = otherArray.capacity();

			#if __cplusplus >= 201400
				values = std::make_unique<Type[]>(capacity());
			#elif __cplusplus >= 201100
				values = std::unique_ptr<Type[]> (new Type[capacity()]);
			#endif

			std::copy(otherArray.begin(), otherArray.end(), this->begin());

			return *this;
		}

		Array& operator=(Array&& otherArray) {

			count_ = std::move(otherArray.count());
			capacity_ = std::move(otherArray.capacity());

			values = move(otherArray.values);
			otherArray.values = nullptr;

			otherArray.count_ = 0;
			otherArray.capacity_ = 0;

			return *this;
		}

		// MARK: Shuffle

		void shuffle() {

			checkIfEmpty();

			#ifdef __APPLE__
				std::mt19937_64 rng(arc4random());
			#else
				std::random_device rd;
				mt19937_64 rng(rd());
			#endif

			std::shuffle(this->begin(), this->end(), rng);
		}

		Array shuffled() const {

			checkIfEmpty();

			Array otherArray(*this);
			otherArray.shuffle();

			return otherArray;
		}

		// MARK: Sort

		void sort() {
			checkIfEmpty();
			std::sort(this->begin(), this->end());
		}

		template <typename Function>
		void sort(const Function& compareFunction) {
			checkIfEmpty();
			std::sort(this->begin(), this->end(), compareFunction);
		}

		template <typename Function>
		Array sorted(const Function& compareFunction) const {

			checkIfEmpty();

			Array otherArray(*this);
			otherArray.sort(compareFunction);

			return otherArray;
		}

		Array sorted() const {

			checkIfEmpty();

			Array otherArray(*this);
			otherArray.sort();

			return otherArray;
		}

		// MARK: Positions

		Type* begin() const {
			checkIfEmpty();
			return &values[0];
		}

		Type* end() const {
			checkIfEmpty();
			return &values[count()];
		}

		Type first() const {
			checkIfEmpty();
			return values[0];
		}

		Type last() const {
			checkIfEmpty();
			return values[count() - 1];
		}
	};
}
<commit_msg>namespaces...<commit_after>#pragma once

#include <initializer_list>
#include "Print-lite.hpp"
#include <algorithm>
#include <stdexcept>
#include <iterator>
#include <memory>
#include <string>
#include <random>

namespace evt {

	template <typename Type>
	class Array {

		// MARK: - Attributes

		std::unique_ptr<Type[]> values { nullptr };
		size_t count_ { 0 };
		size_t capacity_ { 0 };

		// MARK: - Private functions

		template <typename Container>
		void assignNewElements(const Container& elements) {
			count_ = std::distance(std::begin(elements), std::end(elements));
			capacity_ = count_;

			#if __cplusplus >= 201400
				values = std::make_unique<Type[]>(count());
			#elif __cplusplus >= 201100
				values = std::unique_ptr<Type[]>(new Type[count()]);
			#endif

			size_t index = 0;
			for (const auto& element: elements) {
				values[index] = element;
				++index;
			}
		}

		template <typename Container>
		Array& appendNewElements(const Container& newElements) {

			size_t countOfContainer = std::distance(std::begin(newElements), std::end(newElements));

			if (capacity() >= (count() + countOfContainer)) {

				size_t index = count();
				for (const auto& newElement: newElements) {
					values[index] = newElement;
					++index;
				}

				count_ += countOfContainer;
			}
			else {

				size_t newCount = (this->isEmpty()) ? (countOfContainer) : (count() * 2);

				while (newCount < (count() + countOfContainer)) {
					newCount += 2;
				}

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(newCount);
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues (new Type[newCount]);
				#endif

				if (count() > 0) {
					std::copy(this->begin(), this->end(), &newValues[0]);
				}

				size_t index = count();
				for (const auto& element: newElements) {
					newValues[index] = element;
					++index;
				}

				values = move(newValues);

				capacity_ = newCount;
				count_ = count() + countOfContainer;
			}

			return *this;
		}

		// TRUE if elements are the same
		template<typename Container>
		bool compareElements(const Container& elements) const {

			size_t index = 0;
			for (const auto& element: elements) {
				if (values[index] != element) {
					return false;
				}
				++index;
			}

			return true;
		}

		void checkIfEmpty() const {
			if (count() == 0) {
				throw std::length_error("Array is empty (lenght == 0)");
			}
		}

		void checkIfOutOfRange(const size_t index) const {
			if (index >= count()) {
				throw std::out_of_range("Index out of range");
			}
		}

	public:

		// MARK: Constructors

		Array() {}
		template<typename Container>
		Array(const Container& elements) { assignNewElements(elements); }
		Array(const std::initializer_list<Type>& elements) { assignNewElements(elements); }
		explicit Array(const Array& otherArray) { (*this) = otherArray; }

		explicit Array(const int32_t capacity): capacity_(capacity) { // Type can't be size_t because it intefere with the other constructor

			size_t intialCapacity = (capacity < 0) ? (- capacity) : (capacity);

			#if __cplusplus >= 201400
				values = std::make_unique<Type[]>(intialCapacity);
			#elif __cplusplus >= 201100
				values = std::unique_ptr<Type[]>(new Type[intialCapacity]);
			#endif
		}

		size_t count() const { return count_; }
		size_t capacity() const { return capacity_; }

		// MARK: Manage elements

		void insert(const Type& newElement, const size_t index) {

			checkIfOutOfRange(index);

			std::unique_ptr<Type[]> newValues = nullptr;

			if (capacity() == count()) {

				size_t newCount = (this->isEmpty()) ? (2) : (count() * 2);

				#if __cplusplus >= 201400
					newValues = std::make_unique<Type[]>(newCount);
				#elif __cplusplus >= 201100
					newValues = std::unique_ptr<Type[]>(new Type[newCount]);
				#endif

				std::copy(this->begin(), this->end(), &newValues[0]);
				std::copy(&newValues[index], &newValues[count_ + 1], &newValues[index + 1]);

				capacity_ = newCount;
			}
			else {

				#if __cplusplus >= 201400
					newValues = std::make_unique<Type[]>(count());
				#elif __cplusplus >= 201100
					newValues = std::unique_ptr<Type[]>(new Type[count()]);
				#endif

				std::copy(this->begin(), this->end(), &newValues[0]);
				std::copy(&newValues[index], &newValues[count()], &newValues[index + 1]);
			}

			newValues[index] = newElement;

			values = move(newValues);

			count_ += 1;
		}

		void append(const Type& newElement) {

			if (capacity() == count()) {

				size_t newCount = (this->isEmpty()) ? (2) : (count() * 2);

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(newCount);
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues (new Type[newCount]);
				#endif

				if (count() > 0) {
					std::copy(this->begin(), this->end(), &newValues[0]);
				}

				newValues[count()] = newElement;

				values = move(newValues);

				capacity_ = newCount;
			}
			else if (count() < capacity()) {
				values[count()] = newElement;
			}

			count_ += 1;
		}

		template<typename Container>
		void appendElements(const Container& newElements) { (*this) += newElements; }
		void append(const std::initializer_list<Type>& newElements) { (*this) += newElements; }

		void resize(const size_t newSize) {

			if (newSize == 0 && count() > 0 && capacity() > 0 && values != nullptr) {
				removeAll();
			}

			checkIfEmpty();

			if (newSize < capacity()) {
				std::for_each(&values[newSize], this->end(), [](Type& value){ value = Type{}; });
				count_ = newSize;
			}
			else if (newSize > capacity()) {

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(newSize);
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues(new Type[newSize]);
				#endif

				std::copy(this->begin(), this->end(), &newValues[0]);

				values = move(newValues);
				capacity_ = newSize;
			}
		}

		bool shrink() {

			if (capacity() > count()) {

				#if __cplusplus >= 201400
					auto newValues = std::make_unique<Type[]>(count());
				#elif __cplusplus >= 201100
					std::unique_ptr<Type[]> newValues (new Type[count()]);
				#endif

				if (count() > 0) {
					std::copy(this->begin(), this->end(), &newValues[0]);
				}

				values = move(newValues);

				capacity_ = count();

				return true;
			}

			return false;
		}

		void clear() {
			removeAll(true);
		}

		void removeAll(const bool keepCapacity = false) {

			if (keepCapacity) {
				if (values != nullptr) {
					std::for_each(this->begin(), this->end(), [](Type& value){ value = Type{}; });
					count_ = 0;
				}
			}
			else {

				#if __cplusplus >= 201400
					values = std::make_unique<Type[]>(0);
				#elif __cplusplus >= 201100
					values = std::unique_ptr<Type[]>(new Type[0]);
				#endif

				count_ = 0;
				capacity_ = 0;
			}
		}

		void removeAt(const size_t index, const bool shrinkIfEmpty = true) {

			if (count() == 1 && capacity() > 1 && values != nullptr && shrinkIfEmpty) {
				shrink();
			}

			checkIfEmpty();
			checkIfOutOfRange(index);

			std::copy(&values[index + 1], this->end(), &values[index]);
			values[count() - 1] = Type{};

			count_ -= 1;
		}

		void removeLast(const bool shrinkIfEmpty = true) {

			if (count() == 1 && capacity() > 1 && values != nullptr && shrinkIfEmpty) {
				shrink();
			}

			checkIfEmpty();

			values[count()] = Type{};
			count_ -= 1;
		}

		void removeFirst() {
			removeAt(0);
		}

		bool contains(const Type& element) const {
			checkIfEmpty();
			return (std::find(this->begin(), this->end(), element)) != this->end();
		}

		bool isEmpty() const {
			return (count() == 0);
		}

		std::string toString() const {

			if (this->isEmpty()) {
				return "[]";
			}

			std::string output = "[";

			size_t position = 0;
			for (const auto& value: *this) {
				output += quotedString(value);

				if (position+1 < count()) {
					output += ", ";
				}

				++position;
			}

			output += "]";

			return output;
		}

		// MARK: Operators overload

		Type& operator[](const size_t index) {
			checkIfOutOfRange(index);
			return values[index];
		}

		template<typename Container>
		Array& operator+=(const Container& newElements) {
			return appendNewElements(newElements);
		}

		Array& operator+=(const std::initializer_list<Type>& newElements) {
			return appendNewElements(newElements);
		}

		template<typename Container>
		bool operator==(const Container& elements) const {
			return compareElements(elements);
		}

		bool operator==(const std::initializer_list<Type>& elements) const {
			return compareElements(elements);
		}

		template<typename Container>
		bool operator!=(const Container& elements) const {
			return !( (*this) == elements );
		}

		bool operator!=(const std::initializer_list<Type>& elements) const {
			return !( (*this) == elements );
		}

		Array& operator=(const Array& otherArray) {

			count_ = otherArray.count();
			capacity_ = otherArray.capacity();

			#if __cplusplus >= 201400
				values = std::make_unique<Type[]>(capacity());
			#elif __cplusplus >= 201100
				values = std::unique_ptr<Type[]> (new Type[capacity()]);
			#endif

			std::copy(otherArray.begin(), otherArray.end(), this->begin());

			return *this;
		}

		Array& operator=(Array&& otherArray) {

			count_ = std::move(otherArray.count());
			capacity_ = std::move(otherArray.capacity());

			values = move(otherArray.values);
			otherArray.values = nullptr;

			otherArray.count_ = 0;
			otherArray.capacity_ = 0;

			return *this;
		}

		// MARK: Shuffle

		void shuffle() {

			checkIfEmpty();

			#ifdef __APPLE__
				std::mt19937_64 rng(arc4random());
			#else
				std::random_device rd;
				std::mt19937_64 rng(rd());
			#endif

			std::shuffle(this->begin(), this->end(), rng);
		}

		Array shuffled() const {

			checkIfEmpty();

			Array otherArray(*this);
			otherArray.shuffle();

			return otherArray;
		}

		// MARK: Sort

		void sort() {
			checkIfEmpty();
			std::sort(this->begin(), this->end());
		}

		template <typename Function>
		void sort(const Function& compareFunction) {
			checkIfEmpty();
			std::sort(this->begin(), this->end(), compareFunction);
		}

		template <typename Function>
		Array sorted(const Function& compareFunction) const {

			checkIfEmpty();

			Array otherArray(*this);
			otherArray.sort(compareFunction);

			return otherArray;
		}

		Array sorted() const {

			checkIfEmpty();

			Array otherArray(*this);
			otherArray.sort();

			return otherArray;
		}

		// MARK: Positions

		Type* begin() const {
			checkIfEmpty();
			return &values[0];
		}

		Type* end() const {
			checkIfEmpty();
			return &values[count()];
		}

		Type first() const {
			checkIfEmpty();
			return values[0];
		}

		Type last() const {
			checkIfEmpty();
			return values[count() - 1];
		}
	};
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//    of conditions and the following disclaimer in the documentation and/or other
//    materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
//    used to endorse or promote products derived from this software without specific
//    prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "bootstrap_file.h"
#include "blocksdat_file.h"
#include "common/command_line.h"
#include "blockchain_db/blockchain_db.h"
#include "blockchain_db/lmdb/db_lmdb.h"
#include "version.h"

namespace po = boost::program_options;
using namespace epee; // log_space

int main(int argc, char* argv[])
{
  uint32_t log_level = 0;
  uint64_t block_stop = 0;
  bool blocks_dat = false;

  tools::sanitize_locale();

  boost::filesystem::path default_data_path {tools::get_default_data_dir()};
  boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"};
  boost::filesystem::path output_file_path;

  po::options_description desc_cmd_only("Command line options");
  po::options_description desc_cmd_sett("Command line options and settings options");
  const command_line::arg_descriptor<std::string> arg_output_file = {"output-file", "Specify output file", "", true};
  const command_line::arg_descriptor<uint32_t> arg_log_level  = {"log-level",  "", log_level};
  const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
  const command_line::arg_descriptor<bool>     arg_testnet_on = {
    "testnet"
      , "Run on testnet."
      , false
  };
  const command_line::arg_descriptor<bool> arg_blocks_dat = {"blocksdat", "Output in blocks.dat format", blocks_dat};

  command_line::add_arg(desc_cmd_sett, command_line::arg_data_dir, default_data_path.string());
  command_line::add_arg(desc_cmd_sett, command_line::arg_testnet_data_dir, default_testnet_data_path.string());
  command_line::add_arg(desc_cmd_sett, arg_output_file);
  command_line::add_arg(desc_cmd_sett, arg_testnet_on);
  command_line::add_arg(desc_cmd_sett, arg_log_level);
  command_line::add_arg(desc_cmd_sett, arg_block_stop);
  command_line::add_arg(desc_cmd_sett, arg_blocks_dat);

  command_line::add_arg(desc_cmd_only, command_line::arg_help);

  po::options_description desc_options("Allowed options");
  desc_options.add(desc_cmd_only).add(desc_cmd_sett);

  po::variables_map vm;
  bool r = command_line::handle_error_helper(desc_options, [&]()
  {
    po::store(po::parse_command_line(argc, argv, desc_options), vm);
    po::notify(vm);
    return true;
  });
  if (! r)
    return 1;

  if (command_line::get_arg(vm, command_line::arg_help))
  {
    std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
    std::cout << desc_options << std::endl;
    return 1;
  }

  log_level    = command_line::get_arg(vm, arg_log_level);
  block_stop = command_line::get_arg(vm, arg_block_stop);

  log_space::get_set_log_detalisation_level(true, log_level);
  log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
  LOG_PRINT_L0("Starting...");
  LOG_PRINT_L0("Setting log level = " << log_level);

  bool opt_testnet = command_line::get_arg(vm, arg_testnet_on);
  bool opt_blocks_dat = command_line::get_arg(vm, arg_blocks_dat);

  std::string m_config_folder;

  auto data_dir_arg = opt_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir;
  m_config_folder = command_line::get_arg(vm, data_dir_arg);

  if (command_line::has_arg(vm, arg_output_file))
    output_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_output_file));
  else
    output_file_path = boost::filesystem::path(m_config_folder) / "export" / BLOCKCHAIN_RAW;
  LOG_PRINT_L0("Export output file: " << output_file_path.string());

  // If we wanted to use the memory pool, we would set up a fake_core.

#if SOURCE_DB == DB_MEMORY
  // blockchain_storage* core_storage = NULL;
  // tx_memory_pool m_mempool(*core_storage); // is this fake anyway? just passing in NULL! so m_mempool can't be used anyway, right?
  // core_storage = new blockchain_storage(&m_mempool);

  blockchain_storage* core_storage = new blockchain_storage(NULL);
  LOG_PRINT_L0("Initializing source blockchain (in-memory database)");
  r = core_storage->init(m_config_folder, opt_testnet);
#else
  // Use Blockchain instead of lower-level BlockchainDB for two reasons:
  // 1. Blockchain has the init() method for easy setup
  // 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
  //
  // cannot match blockchain_storage setup above with just one line,
  // e.g.
  //   Blockchain* core_storage = new Blockchain(NULL);
  // because unlike blockchain_storage constructor, which takes a pointer to
  // tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
  LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
  Blockchain* core_storage = NULL;
  tx_memory_pool m_mempool(*core_storage);
  core_storage = new Blockchain(m_mempool);

  BlockchainDB* db = new BlockchainLMDB();
  boost::filesystem::path folder(m_config_folder);
  folder /= db->get_db_name();
  int lmdb_flags = 0;
  lmdb_flags |= MDB_RDONLY;
  const std::string filename = folder.string();

  LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
  try
  {
    db->open(filename, lmdb_flags);
  }
  catch (const std::exception& e)
  {
    LOG_PRINT_L0("Error opening database: " << e.what());
    return 1;
  }
  r = core_storage->init(db, opt_testnet);
#endif

  CHECK_AND_ASSERT_MES(r, false, "Failed to initialize source blockchain storage");
  LOG_PRINT_L0("Source blockchain storage initialized OK");
  LOG_PRINT_L0("Exporting blockchain raw data...");

  if (opt_blocks_dat)
  {
    BlocksdatFile blocksdat;
    r = blocksdat.store_blockchain_raw(core_storage, NULL, output_file_path, block_stop);
  }
  else
  {
    BootstrapFile bootstrap;
    r = bootstrap.store_blockchain_raw(core_storage, NULL, output_file_path, block_stop);
  }
  CHECK_AND_ASSERT_MES(r, false, "Failed to export blockchain raw data");
  LOG_PRINT_L0("Blockchain raw data exported OK");
}
<commit_msg>blockchain_export: Support BerkeleyDB<commit_after>// Copyright (c) 2014-2016, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//    of conditions and the following disclaimer in the documentation and/or other
//    materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
//    used to endorse or promote products derived from this software without specific
//    prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "bootstrap_file.h"
#include "blocksdat_file.h"
#include "common/command_line.h"
#include "blockchain_db/blockchain_db.h"
#include "blockchain_db/lmdb/db_lmdb.h"
#if defined(BERKELEY_DB)
#include "blockchain_db/berkeleydb/db_bdb.h"
#endif
#include "blockchain_db/db_types.h"
#include "version.h"

namespace po = boost::program_options;
using namespace epee; // log_space

std::string join_set_strings(const std::unordered_set<std::string>& db_types_all, const char* delim)
{
  std::string result;
  std::ostringstream s;
  std::copy(db_types_all.begin(), db_types_all.end(), std::ostream_iterator<std::string>(s, delim));
  result = s.str();
  if (result.length() > 0)
    result.erase(result.end()-strlen(delim), result.end());
  return result;
}

int main(int argc, char* argv[])
{
#if defined(BLOCKCHAIN_DB) && (BLOCKCHAIN_DB == DB_MEMORY)
  std::string default_db_type = "memory";
#else
  std::string default_db_type = "lmdb";
#endif

  std::unordered_set<std::string> db_types_all = cryptonote::blockchain_db_types;
  db_types_all.insert("memory");

  std::string available_dbs = join_set_strings(db_types_all, ", ");
  available_dbs = "available: " + available_dbs;

  uint32_t log_level = 0;
  uint64_t block_stop = 0;
  bool blocks_dat = false;

  tools::sanitize_locale();

  boost::filesystem::path default_data_path {tools::get_default_data_dir()};
  boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"};
  boost::filesystem::path output_file_path;

  po::options_description desc_cmd_only("Command line options");
  po::options_description desc_cmd_sett("Command line options and settings options");
  const command_line::arg_descriptor<std::string> arg_output_file = {"output-file", "Specify output file", "", true};
  const command_line::arg_descriptor<uint32_t> arg_log_level  = {"log-level",  "", log_level};
  const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
  const command_line::arg_descriptor<bool>     arg_testnet_on = {
    "testnet"
      , "Run on testnet."
      , false
  };
  const command_line::arg_descriptor<std::string> arg_database = {
    "database", available_dbs.c_str(), default_db_type
  };
  const command_line::arg_descriptor<bool> arg_blocks_dat = {"blocksdat", "Output in blocks.dat format", blocks_dat};

  command_line::add_arg(desc_cmd_sett, command_line::arg_data_dir, default_data_path.string());
  command_line::add_arg(desc_cmd_sett, command_line::arg_testnet_data_dir, default_testnet_data_path.string());
  command_line::add_arg(desc_cmd_sett, arg_output_file);
  command_line::add_arg(desc_cmd_sett, arg_testnet_on);
  command_line::add_arg(desc_cmd_sett, arg_log_level);
  command_line::add_arg(desc_cmd_sett, arg_database);
  command_line::add_arg(desc_cmd_sett, arg_block_stop);
  command_line::add_arg(desc_cmd_sett, arg_blocks_dat);

  command_line::add_arg(desc_cmd_only, command_line::arg_help);

  po::options_description desc_options("Allowed options");
  desc_options.add(desc_cmd_only).add(desc_cmd_sett);

  po::variables_map vm;
  bool r = command_line::handle_error_helper(desc_options, [&]()
  {
    po::store(po::parse_command_line(argc, argv, desc_options), vm);
    po::notify(vm);
    return true;
  });
  if (! r)
    return 1;

  if (command_line::get_arg(vm, command_line::arg_help))
  {
    std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
    std::cout << desc_options << std::endl;
    return 1;
  }

  log_level    = command_line::get_arg(vm, arg_log_level);
  block_stop = command_line::get_arg(vm, arg_block_stop);

  log_space::get_set_log_detalisation_level(true, log_level);
  log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
  LOG_PRINT_L0("Starting...");
  LOG_PRINT_L0("Setting log level = " << log_level);

  bool opt_testnet = command_line::get_arg(vm, arg_testnet_on);
  bool opt_blocks_dat = command_line::get_arg(vm, arg_blocks_dat);

  std::string m_config_folder;

  auto data_dir_arg = opt_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir;
  m_config_folder = command_line::get_arg(vm, data_dir_arg);

  std::string db_type = command_line::get_arg(vm, arg_database);
  if (db_types_all.count(db_type) == 0)
  {
    std::cerr << "Invalid database type: " << db_type << std::endl;
    return 1;
  }
#if !defined(BERKELEY_DB)
  if (db_type == "berkeley")
  {
    LOG_ERROR("BerkeleyDB support disabled.");
    return false;
  }
#endif

  if (command_line::has_arg(vm, arg_output_file))
    output_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_output_file));
  else
    output_file_path = boost::filesystem::path(m_config_folder) / "export" / BLOCKCHAIN_RAW;
  LOG_PRINT_L0("Export output file: " << output_file_path.string());

  // If we wanted to use the memory pool, we would set up a fake_core.

#if SOURCE_DB == DB_MEMORY
  // blockchain_storage* core_storage = NULL;
  // tx_memory_pool m_mempool(*core_storage); // is this fake anyway? just passing in NULL! so m_mempool can't be used anyway, right?
  // core_storage = new blockchain_storage(&m_mempool);

  blockchain_storage* core_storage = new blockchain_storage(NULL);
  LOG_PRINT_L0("Initializing source blockchain (in-memory database)");
  r = core_storage->init(m_config_folder, opt_testnet);
#else
  // Use Blockchain instead of lower-level BlockchainDB for two reasons:
  // 1. Blockchain has the init() method for easy setup
  // 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
  //
  // cannot match blockchain_storage setup above with just one line,
  // e.g.
  //   Blockchain* core_storage = new Blockchain(NULL);
  // because unlike blockchain_storage constructor, which takes a pointer to
  // tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
  LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
  Blockchain* core_storage = NULL;
  tx_memory_pool m_mempool(*core_storage);
  core_storage = new Blockchain(m_mempool);

  int db_flags = 0;

  BlockchainDB* db = nullptr;
  if (db_type == "lmdb")
  {
    db_flags |= MDB_RDONLY;
    db = new BlockchainLMDB();
  }
#if defined(BERKELEY_DB)
  else if (db_type == "berkeley")
    db = new BlockchainBDB();
#endif
  else
  {
    LOG_ERROR("Attempted to use non-existent database type: " << db_type);
    throw std::runtime_error("Attempting to use non-existent database type");
  }
  LOG_PRINT_L0("database: " << db_type);

  boost::filesystem::path folder(m_config_folder);
  folder /= db->get_db_name();
  const std::string filename = folder.string();

  LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
  try
  {
    db->open(filename, db_flags);
  }
  catch (const std::exception& e)
  {
    LOG_PRINT_L0("Error opening database: " << e.what());
    return 1;
  }
  r = core_storage->init(db, opt_testnet);
#endif

  CHECK_AND_ASSERT_MES(r, false, "Failed to initialize source blockchain storage");
  LOG_PRINT_L0("Source blockchain storage initialized OK");
  LOG_PRINT_L0("Exporting blockchain raw data...");

  if (opt_blocks_dat)
  {
    BlocksdatFile blocksdat;
    r = blocksdat.store_blockchain_raw(core_storage, NULL, output_file_path, block_stop);
  }
  else
  {
    BootstrapFile bootstrap;
    r = bootstrap.store_blockchain_raw(core_storage, NULL, output_file_path, block_stop);
  }
  CHECK_AND_ASSERT_MES(r, false, "Failed to export blockchain raw data");
  LOG_PRINT_L0("Blockchain raw data exported OK");
}
<|endoftext|>


<commit_before>#include "log.h"

#include <array>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace allpix;

// NOTE: we have to check for exceptions before we do the actual logging (which may also throw exceptions)
DefaultLogger::DefaultLogger() : os(), exception_count_(get_uncaught_exceptions(true)), indent_count_(0) {}

DefaultLogger::~DefaultLogger() {
    // check if it is potentially safe to throw
    if(exception_count_ != get_uncaught_exceptions(false)) {
        return;
    }

    // get output string
    std::string out(os.str());

    // replace every newline by indented code if necessary
    auto start_pos = out.find('\n');
    if(start_pos != std::string::npos) {
        std::string spcs(indent_count_ + 1, ' ');
        spcs[0] = '\n';
        do {
            out.replace(start_pos, 1, spcs);
            start_pos += spcs.length();
        } while((start_pos = out.find('\n', start_pos)) != std::string::npos);
    }

    // add final newline
    out += '\n';

    // print output to streams
    for(auto stream : get_streams()) {
        (*stream) << out;
    }
}

std::ostringstream&
DefaultLogger::getStream(LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    os << "[" << get_current_date() << "] ";
    /*if (logName().size() > 0) {
        os << "<" << logName() << "> ";
    }*/
    os << std::setw(8) << getStringFromLevel(level) << ": ";

    // For debug levels we want also function name and line number printed:
    if(level != LogLevel::INFO && level != LogLevel::QUIET && level != LogLevel::WARNING) {
        os << "<" << file << "/" << function << ":L" << line << "> ";
    }

    indent_count_ = static_cast<unsigned int>(os.str().size());
    return os;
}

// set reporting level
LogLevel& DefaultLogger::get_reporting_level() {
    static LogLevel reporting_level;
    return reporting_level;
}
void DefaultLogger::setReportingLevel(LogLevel level) {
    get_reporting_level() = level;
}

LogLevel DefaultLogger::getReportingLevel() {
    return get_reporting_level();
}

// change streams
std::vector<std::ostream*>& DefaultLogger::get_streams() {
    static std::vector<std::ostream*> streams = {&std::cerr};
    return streams;
}
const std::vector<std::ostream*>& DefaultLogger::getStreams() {
    return get_streams();
}
void DefaultLogger::clearStreams() {
    get_streams().clear();
}
void DefaultLogger::addStream(std::ostream& stream) {
    get_streams().push_back(&stream);
}

// convert string to log level and vice versa
std::string DefaultLogger::getStringFromLevel(LogLevel level) {
    static const std::array<std::string, 6> type = {{"QUIET", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"}};
    return type.at(static_cast<decltype(type)::size_type>(level));
}

LogLevel DefaultLogger::getLevelFromString(const std::string& level) {
    if(level == "DEBUG") {
        return LogLevel::DEBUG;
    }
    if(level == "INFO") {
        return LogLevel::INFO;
    }
    if(level == "WARNING") {
        return LogLevel::WARNING;
    }
    if(level == "ERROR") {
        return LogLevel::ERROR;
    }
    if(level == "CRITICAL") {
        return LogLevel::CRITICAL;
    }
    if(level == "QUIET") {
        return LogLevel::QUIET;
    }

    DefaultLogger().getStream(LogLevel::WARNING) << "Unknown logging level '" << level
                                                 << "'. Using WARNING level as default.";
    return LogLevel::WARNING;
}

std::string DefaultLogger::get_current_date() {
    // FIXME: revise this to get microseconds in a better way
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%X");

    auto seconds_from_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() - seconds_from_epoch).count();
    ss << "." << millis;
    return ss.str();
}

int DefaultLogger::get_uncaught_exceptions(bool cons = false) {
#if __cplusplus > 201402L
    // we can only do this fully correctly in C++17
    return std::uncaught_exceptions();
#else
    if(cons) {
        return 0;
    }
    return static_cast<int>(std::uncaught_exception());
#endif
}
<commit_msg>always use 3 digits for milliseconds in log<commit_after>#include "log.h"

#include <array>
#include <chrono>
#include <exception>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <string>

using namespace allpix;

// NOTE: we have to check for exceptions before we do the actual logging (which may also throw exceptions)
DefaultLogger::DefaultLogger() : os(), exception_count_(get_uncaught_exceptions(true)), indent_count_(0) {}

DefaultLogger::~DefaultLogger() {
    // check if it is potentially safe to throw
    if(exception_count_ != get_uncaught_exceptions(false)) {
        return;
    }

    // get output string
    std::string out(os.str());

    // replace every newline by indented code if necessary
    auto start_pos = out.find('\n');
    if(start_pos != std::string::npos) {
        std::string spcs(indent_count_ + 1, ' ');
        spcs[0] = '\n';
        do {
            out.replace(start_pos, 1, spcs);
            start_pos += spcs.length();
        } while((start_pos = out.find('\n', start_pos)) != std::string::npos);
    }

    // add final newline
    out += '\n';

    // print output to streams
    for(auto stream : get_streams()) {
        (*stream) << out;
    }
}

std::ostringstream&
DefaultLogger::getStream(LogLevel level, const std::string& file, const std::string& function, uint32_t line) {
    os << "[" << get_current_date() << "] ";
    /*if (logName().size() > 0) {
        os << "<" << logName() << "> ";
    }*/
    os << std::setw(8) << getStringFromLevel(level) << ": ";

    // For debug levels we want also function name and line number printed:
    if(level != LogLevel::INFO && level != LogLevel::QUIET && level != LogLevel::WARNING) {
        os << "<" << file << "/" << function << ":L" << line << "> ";
    }

    indent_count_ = static_cast<unsigned int>(os.str().size());
    return os;
}

// set reporting level
LogLevel& DefaultLogger::get_reporting_level() {
    static LogLevel reporting_level;
    return reporting_level;
}
void DefaultLogger::setReportingLevel(LogLevel level) {
    get_reporting_level() = level;
}

LogLevel DefaultLogger::getReportingLevel() {
    return get_reporting_level();
}

// change streams
std::vector<std::ostream*>& DefaultLogger::get_streams() {
    static std::vector<std::ostream*> streams = {&std::cerr};
    return streams;
}
const std::vector<std::ostream*>& DefaultLogger::getStreams() {
    return get_streams();
}
void DefaultLogger::clearStreams() {
    get_streams().clear();
}
void DefaultLogger::addStream(std::ostream& stream) {
    get_streams().push_back(&stream);
}

// convert string to log level and vice versa
std::string DefaultLogger::getStringFromLevel(LogLevel level) {
    static const std::array<std::string, 6> type = {{"QUIET", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"}};
    return type.at(static_cast<decltype(type)::size_type>(level));
}

LogLevel DefaultLogger::getLevelFromString(const std::string& level) {
    if(level == "DEBUG") {
        return LogLevel::DEBUG;
    }
    if(level == "INFO") {
        return LogLevel::INFO;
    }
    if(level == "WARNING") {
        return LogLevel::WARNING;
    }
    if(level == "ERROR") {
        return LogLevel::ERROR;
    }
    if(level == "CRITICAL") {
        return LogLevel::CRITICAL;
    }
    if(level == "QUIET") {
        return LogLevel::QUIET;
    }

    DefaultLogger().getStream(LogLevel::WARNING) << "Unknown logging level '" << level
                                                 << "'. Using WARNING level as default.";
    return LogLevel::WARNING;
}

std::string DefaultLogger::get_current_date() {
    // FIXME: revise this to get microseconds in a better way
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%X");

    auto seconds_from_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch() - seconds_from_epoch).count();
    ss << ".";
    ss << std::setfill('0') << std::setw(3);
    ss << millis;
    return ss.str();
}

int DefaultLogger::get_uncaught_exceptions(bool cons = false) {
#if __cplusplus > 201402L
    // we can only do this fully correctly in C++17
    return std::uncaught_exceptions();
#else
    if(cons) {
        return 0;
    }
    return static_cast<int>(std::uncaught_exception());
#endif
}
<|endoftext|>


<commit_before>#include "shell.h"
#include "runtime.h"
#include <sstream>
#include <iomanip>
#include <set>

using namespace elpa;

template<class Env>
auto Shell<Env>::process_command( const std::string& cmd, elpa_istream& eis ) -> bool
{
    eis >> nomoreinput;

    if( cmd == "quit" || cmd == "exit" )
        return false;
    else if( cmd == "flat" )
        _format = flat;
    else if( cmd == "deep" )
        _format = deep;
    else if( cmd == "line" )
        _line_format = true;
    else if( cmd == "list" )
        _line_format = false;
    else
        throw Error<Command>( "Unknown command '"s + cmd + "'" );

    return true;
}

template<class Env>
auto Shell<Env>::process_input( const std::string& input ) -> bool
{
    std::istringstream iss( input );
    elpa_istream eis( iss, _manager.interpreter().allocator(), _names );
	elpa_ostream eos( _out );

    char c;
    if( eis >> c )
    {
        if( c == ':' )
        {
            std::string cmd;
            if( !(eis >> std::noskipws >> cmd >> std::skipws) )
                throw Error<Syntax>( "Expected command after ':'" );

            return process_command( cmd, eis );
        }
        else
        {
            if( !_manager.is_valid_operator( c ) )
            {
                eis.putback( c );
                c = '\0';
            }

            try
            {
                elem_t elem;
                eis >> elem >> nomoreinput;

                if( c != '\0' )
                    elem = _manager.process_operator( c, elem );

                _names["it"] = elem;

				eos << _format;
                if( !_line_format )
                    for( ; elem.is_pcell(); elem = elem.pcell()->tail() )
                        eos << elem.pcell()->head() << std::endl;

                eos << elem << std::endl;

                return true;
            }
            catch( const Error<Syntax,EOS>& )
            {
                throw MoreToRead();
            }
        }
    }

    return true;
}

template<class Env>
void Shell<Env>::go()
{
    bool keep_processing = true;
    while( keep_processing )
    {
        try
        {
            std::string input;

            std::string prompt = ">>> ";
            while( true )
            {
                try
                {
                    _out << prompt;
                    std::string line;
                    std::getline( _in, line );
                    input += (line + "\n"s);
                    prompt = "... ";

                    keep_processing = process_input( input );
                    break;
                }
                catch( const MoreToRead& )
                {
                }
            }
        }
        catch( const Error<Syntax>& e )
        {
            _out << "Syntax: " << e.message() << std::endl;
        }
        catch( const Error<Command>& e )
        {
            _out << "Command: " << e.message() << std::endl;
        }
    }
}

#include "../kcon/interpreter.h"
#include "../kcon/shell.h"
template class Shell< Env<Debug, SimpleScheme, TestAllocator, kcon::KConInterpreter> >;<commit_msg>Adding def command<commit_after>#include "shell.h"
#include "runtime.h"
#include <sstream>
#include <iomanip>
#include <set>

using namespace elpa;

template<class Env>
auto Shell<Env>::process_command( const std::string& cmd, elpa_istream& eis ) -> bool
{
	if( cmd == "def" )
    {
    	std::string name;
    	elem_t elem;
    	eis >> name >> elem >> nomoreinput;
    	_names[name] = elem;
    	return true;
    }

    eis >> nomoreinput;

    if( cmd == "quit" || cmd == "exit" )
        return false;
    else if( cmd == "flat" )
        _format = flat;
    else if( cmd == "deep" )
        _format = deep;
    else if( cmd == "line" )
        _line_format = true;
    else if( cmd == "list" )
        _line_format = false;
    else
        throw Error<Command>( "Unknown command '"s + cmd + "'" );

    return true;
}

template<class Env>
auto Shell<Env>::process_input( const std::string& input ) -> bool
{
    std::istringstream iss( input );
    elpa_istream eis( iss, _manager.interpreter().allocator(), _names );
	elpa_ostream eos( _out );

    char c;
    if( eis >> c )
    {
        if( c == ':' )
        {
            std::string cmd;
            if( !(eis >> std::noskipws >> cmd >> std::skipws) )
                throw Error<Syntax>( "Expected command after ':'" );

            return process_command( cmd, eis );
        }
        else
        {
            if( !_manager.is_valid_operator( c ) )
            {
                eis.putback( c );
                c = '\0';
            }

            try
            {
                elem_t elem;
                eis >> elem >> nomoreinput;

                if( c != '\0' )
                    elem = _manager.process_operator( c, elem );

                _names["it"] = elem;

				eos << _format;
                if( !_line_format )
                    for( ; elem.is_pcell(); elem = elem.pcell()->tail() )
                        eos << elem.pcell()->head() << std::endl;

                eos << elem << std::endl;

                return true;
            }
            catch( const Error<Syntax,EOS>& )
            {
                throw MoreToRead();
            }
        }
    }

    return true;
}

template<class Env>
void Shell<Env>::go()
{
    bool keep_processing = true;
    while( keep_processing )
    {
        try
        {
            std::string input;

            std::string prompt = ">>> ";
            while( true )
            {
                try
                {
                    _out << prompt;
                    std::string line;
                    std::getline( _in, line );
                    input += (line + "\n"s);
                    prompt = "... ";

                    keep_processing = process_input( input );
                    break;
                }
                catch( const MoreToRead& )
                {
                }
            }
        }
        catch( const Error<Syntax>& e )
        {
            _out << "Syntax: " << e.message() << std::endl;
        }
        catch( const Error<Command>& e )
        {
            _out << "Command: " << e.message() << std::endl;
        }
    }
}

#include "../kcon/interpreter.h"
#include "../kcon/shell.h"
template class Shell< Env<Debug, SimpleScheme, TestAllocator, kcon::KConInterpreter> >;<|endoftext|>