<commit_before>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011, 2012                                                   *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation, either version 3 of the License                  *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa 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 Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_SCHEDULER_HPP
#define CPPA_SCHEDULER_HPP

#include <chrono>
#include <memory>
#include <cstdint>
#include <functional>

#include "cppa/atom.hpp"
#include "cppa/actor.hpp"
#include "cppa/channel.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/scheduling_hint.hpp"

#include "cppa/util/duration.hpp"

namespace cppa {

class self_type;
class scheduled_actor;
class scheduler_helper;

typedef std::function<void()> void_function;
typedef std::function<void(local_actor*)> init_callback;

namespace detail {
// forwards self_type as actor_ptr, otherwise equal to std::forward
template<typename T>
struct spawn_fwd_ {
    static inline T&& _(T&& arg) { return std::move(arg); }
    static inline T& _(T& arg) { return arg; }
    static inline const T& _(const T& arg) { return arg; }
};
template<>
struct spawn_fwd_<self_type> {
    static inline actor_ptr _(const self_type& s) { return s.get(); }
};
class singleton_manager;
} // namespace detail

/**
 * @brief
 */
class scheduler {

    scheduler_helper* m_helper;

    channel* delayed_send_helper();

    friend class detail::singleton_manager;

 protected:

    scheduler();

    virtual ~scheduler();

    /**
     * @warning Always call scheduler::initialize on overriding.
     */
    virtual void initialize();

    /**
     * @warning Always call scheduler::destroy on overriding.
     */
    virtual void destroy();

 private:

    static scheduler* create_singleton();

    inline void dispose() { delete this; }

 public:

    const actor_ptr& printer() const;

    virtual void enqueue(scheduled_actor*) = 0;

    /**
     * @brief Informs the scheduler about a converted context
     *        (a thread that acts as actor).
     * @note Calls <tt>what->attach(...)</tt>.
     */
    virtual void register_converted_context(actor* what);

    /**
     * @brief Informs the scheduler about a hidden (non-actor)
     *        context that should be counted by await_others_done().
     * @returns An {@link attachable} that the hidden context has to destroy
     *         if his lifetime ends.
     */
    virtual attachable* register_hidden_context();

    template<typename Duration, typename... Data>
    void delayed_send(const channel_ptr& to,
                      const Duration& rel_time,
                      any_tuple data           ) {
        auto tup = make_any_tuple(atom("SEND"),
                                  util::duration{rel_time},
                                  to,
                                  std::move(data));
        delayed_send_helper()->enqueue(self, std::move(tup));
    }

    template<typename Duration, typename... Data>
    void delayed_reply(const actor_ptr& to,
                       const Duration& rel_time,
                       message_id_t id,
                       any_tuple data           ) {
        CPPA_REQUIRE(!id.valid() || id.is_response());
        if (id.valid()) {
            auto tup = make_any_tuple(atom("REPLY"),
                                      util::duration{rel_time},
                                      to,
                                      id,
                                      std::move(data));
            delayed_send_helper()->enqueue(self, std::move(tup));
        }
        else {
            this->delayed_send(to, rel_time, std::move(data));
        }
    }

    /**
     * @brief Spawns a new actor that executes fun()
     *        with the scheduling policy @p hint if possible.
     */
    virtual actor_ptr spawn(void_function fun, scheduling_hint hint) = 0;

    /**
     * @brief Spawns a new actor that executes behavior()
     *        with the scheduling policy @p hint if possible and calls
     *        init_cb after the actor is initialized but before
     *        it starts execution.
     */
    virtual actor_ptr spawn(void_function fun,
                            init_callback init_cb,
                            scheduling_hint hint) = 0;

    /**
     * @brief Spawns a new event-based actor.
     */
    virtual actor_ptr spawn(scheduled_actor* what,
                            scheduling_hint hint = scheduled) = 0;

    /**
     * @brief Spawns a new event-based actor and calls
     *        init_cb after the actor is initialized but before
     *        it starts execution.
     */
    virtual actor_ptr spawn(scheduled_actor* what,
                            init_callback init_cb,
                            scheduling_hint hint = scheduled) = 0;

    // hide implementation details for documentation
#   ifndef CPPA_DOCUMENTATION

    template<typename Fun, typename Arg0, typename... Args>
    actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun, Arg0&& arg0, Args&&... args) {
        return this->spawn(
                    std::bind(
                        std::forward<Fun>(fun),
                        detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
                        detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
                    hint);
    }

    template<typename Fun>
    actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun) {
        return this->spawn(std::forward<Fun>(fun), hint);
    }

    template<typename InitCallback, typename Fun, typename Arg0, typename... Args>
    actor_ptr spawn_cb_impl(scheduling_hint hint,
                            InitCallback&& init_cb,
                            Fun&& fun, Arg0&& arg0, Args&&... args) {
        return this->spawn(
                    std::bind(
                        std::forward<Fun>(fun),
                        detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
                        detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
                    std::forward<InitCallback>(init_cb),
                    hint);
    }

    template<typename InitCallback, typename Fun>
    actor_ptr spawn_cb_impl(scheduling_hint hint, InitCallback&& init_cb, Fun&& fun) {
        return this->spawn(std::forward<Fun>(fun),
                           std::forward<InitCallback>(init_cb),
                           hint);
    }

#   endif // CPPA_DOCUMENTATION

};

/**
 * @brief Sets the scheduler to @p sched.
 * @param sched A user-defined scheduler implementation.
 * @pre <tt>sched != nullptr</tt>.
 * @throws std::runtime_error if there's already a scheduler defined.
 */
void set_scheduler(scheduler* sched);

/**
 * @brief Sets a thread pool scheduler with @p num_threads worker threads.
 * @throws std::runtime_error if there's already a scheduler defined.
 */
void set_default_scheduler(size_t num_threads);

/**
 * @brief Returns the currently running scheduler.
 */
scheduler* get_scheduler();

} // namespace cppa::detail

#endif // CPPA_SCHEDULER_HPP
<commit_msg>documentation update for scheduler<commit_after>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011, 2012                                                   *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa is free software: you can redistribute it and/or modify it under   *
 * the terms of the GNU Lesser General Public License as published by the     *
 * Free Software Foundation, either version 3 of the License                  *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa 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 Lesser General Public License for more details.                *
 *                                                                            *
 * You should have received a copy of the GNU Lesser General Public License   *
 * along with libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_SCHEDULER_HPP
#define CPPA_SCHEDULER_HPP

#include <chrono>
#include <memory>
#include <cstdint>
#include <functional>

#include "cppa/atom.hpp"
#include "cppa/actor.hpp"
#include "cppa/channel.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/scheduling_hint.hpp"

#include "cppa/util/duration.hpp"

namespace cppa {

class self_type;
class scheduled_actor;
class scheduler_helper;

typedef std::function<void()> void_function;
typedef std::function<void(local_actor*)> init_callback;

namespace detail {
// forwards self_type as actor_ptr, otherwise equal to std::forward
template<typename T>
struct spawn_fwd_ {
    static inline T&& _(T&& arg) { return std::move(arg); }
    static inline T& _(T& arg) { return arg; }
    static inline const T& _(const T& arg) { return arg; }
};
template<>
struct spawn_fwd_<self_type> {
    static inline actor_ptr _(const self_type& s) { return s.get(); }
};
class singleton_manager;
} // namespace detail

/**
 * @brief This abstract class allows to create (spawn) new actors
 *        and offers delayed sends.
 */
class scheduler {

    scheduler_helper* m_helper;

    channel* delayed_send_helper();

    friend class detail::singleton_manager;

 protected:

    scheduler();

    virtual ~scheduler();

    /**
     * @warning Always call scheduler::initialize on overriding.
     */
    virtual void initialize();

    /**
     * @warning Always call scheduler::destroy on overriding.
     */
    virtual void destroy();

 private:

    static scheduler* create_singleton();

    inline void dispose() { delete this; }

 public:

    const actor_ptr& printer() const;

    virtual void enqueue(scheduled_actor*) = 0;

    /**
     * @brief Informs the scheduler about a converted context
     *        (a thread that acts as actor).
     * @note Calls <tt>what->attach(...)</tt>.
     */
    virtual void register_converted_context(actor* what);

    /**
     * @brief Informs the scheduler about a hidden (non-actor)
     *        context that should be counted by await_others_done().
     * @returns An {@link attachable} that the hidden context has to destroy
     *         if his lifetime ends.
     */
    virtual attachable* register_hidden_context();

    template<typename Duration, typename... Data>
    void delayed_send(const channel_ptr& to,
                      const Duration& rel_time,
                      any_tuple data           ) {
        auto tup = make_any_tuple(atom("SEND"),
                                  util::duration{rel_time},
                                  to,
                                  std::move(data));
        delayed_send_helper()->enqueue(self, std::move(tup));
    }

    template<typename Duration, typename... Data>
    void delayed_reply(const actor_ptr& to,
                       const Duration& rel_time,
                       message_id_t id,
                       any_tuple data           ) {
        CPPA_REQUIRE(!id.valid() || id.is_response());
        if (id.valid()) {
            auto tup = make_any_tuple(atom("REPLY"),
                                      util::duration{rel_time},
                                      to,
                                      id,
                                      std::move(data));
            delayed_send_helper()->enqueue(self, std::move(tup));
        }
        else {
            this->delayed_send(to, rel_time, std::move(data));
        }
    }

    /**
     * @brief Spawns a new actor that executes fun()
     *        with the scheduling policy @p hint if possible.
     */
    virtual actor_ptr spawn(void_function fun, scheduling_hint hint) = 0;

    /**
     * @brief Spawns a new actor that executes behavior()
     *        with the scheduling policy @p hint if possible and calls
     *        init_cb after the actor is initialized but before
     *        it starts execution.
     */
    virtual actor_ptr spawn(void_function fun,
                            init_callback init_cb,
                            scheduling_hint hint) = 0;

    /**
     * @brief Spawns a new event-based actor.
     */
    virtual actor_ptr spawn(scheduled_actor* what,
                            scheduling_hint hint = scheduled) = 0;

    /**
     * @brief Spawns a new event-based actor and calls
     *        init_cb after the actor is initialized but before
     *        it starts execution.
     */
    virtual actor_ptr spawn(scheduled_actor* what,
                            init_callback init_cb,
                            scheduling_hint hint = scheduled) = 0;

    // hide implementation details for documentation
#   ifndef CPPA_DOCUMENTATION

    template<typename Fun, typename Arg0, typename... Args>
    actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun, Arg0&& arg0, Args&&... args) {
        return this->spawn(
                    std::bind(
                        std::forward<Fun>(fun),
                        detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
                        detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
                    hint);
    }

    template<typename Fun>
    actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun) {
        return this->spawn(std::forward<Fun>(fun), hint);
    }

    template<typename InitCallback, typename Fun, typename Arg0, typename... Args>
    actor_ptr spawn_cb_impl(scheduling_hint hint,
                            InitCallback&& init_cb,
                            Fun&& fun, Arg0&& arg0, Args&&... args) {
        return this->spawn(
                    std::bind(
                        std::forward<Fun>(fun),
                        detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
                        detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
                    std::forward<InitCallback>(init_cb),
                    hint);
    }

    template<typename InitCallback, typename Fun>
    actor_ptr spawn_cb_impl(scheduling_hint hint, InitCallback&& init_cb, Fun&& fun) {
        return this->spawn(std::forward<Fun>(fun),
                           std::forward<InitCallback>(init_cb),
                           hint);
    }

#   endif // CPPA_DOCUMENTATION

};

/**
 * @brief Sets the scheduler to @p sched.
 * @param sched A user-defined scheduler implementation.
 * @pre <tt>sched != nullptr</tt>.
 * @throws std::runtime_error if there's already a scheduler defined.
 */
void set_scheduler(scheduler* sched);

/**
 * @brief Sets a thread pool scheduler with @p num_threads worker threads.
 * @throws std::runtime_error if there's already a scheduler defined.
 */
void set_default_scheduler(size_t num_threads);

/**
 * @brief Returns the currently running scheduler.
 */
scheduler* get_scheduler();

} // namespace cppa

#endif // CPPA_SCHEDULER_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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.
#pragma once

#include <algorithm>
#include <tuple>
#include "helper.hh"

namespace wrencc::tree {

using ColorType = bool;
static constexpr ColorType kColorRed = false;
static constexpr ColorType kColorBlk = true;
static constexpr int kHeightMark = 0xff;

struct NodeBase;
struct AVLNodeBase;
struct RBNodeBase;
using BasePtr       = NodeBase*;
using ConstBasePtr  = const NodeBase*;

namespace impl::avl {
  void insert(bool insert_left, BasePtr x, BasePtr p, NodeBase& header) noexcept;
  void erase(BasePtr x, NodeBase& root) noexcept;
}

namespace impl::rb {
  void insert(bool insert_left, BasePtr x, BasePtr p, NodeBase& header) noexcept;
  void erase(BasePtr x, NodeBase& header) noexcept;
}

struct NodeBase {
  BasePtr parent;
  BasePtr left;
  BasePtr right;

  template <typename AVL = AVLNodeBase> inline AVL* as_avl() noexcept {
    return static_cast<AVL*>(this);
  }

  template <typename RB = AVLNodeBase> inline RB* as_rb() noexcept {
    return static_cast<RB*>(this);
  }

  static BasePtr successor(BasePtr x) noexcept {
    if (x->right != nullptr) {
      x = x->right;
      while (x->left != nullptr)
        x = x->left;
    }
    else {
      BasePtr y = x->parent;
      while (x == y->right) {
        x = y;
        y = y->parent;
      }
      if (x->right != y)
        x = y;
    }
    return x;
  }

  template <typename HeadChecker>
  static BasePtr predecessor(BasePtr x, HeadChecker&& checker) noexcept {
    if (checker(x) && x->parent->parent == x) {
      x = x->right;
    }
    else if (x->left != nullptr) {
      x = x->left;
      while (x->right != nullptr)
        x = x->right;
    }
    else {
      BasePtr y = x->parent;
      while (x == y->left) {
        x = y;
        y = y->parent;
      }
      x = y;
    }
    return x;
  }
};

struct AVLNodeBase : public NodeBase {
  int height;

  inline void set_marker() noexcept { height = kHeightMark; }
  inline bool is_marker() const noexcept { return height == kHeightMark; }
  inline void set_height(int h) noexcept { height = h; }

  inline int lheight() const noexcept {
    return left != nullptr ? left->as_avl()->height : 0;
  }

  inline int rheight() const noexcept {
    return right != nullptr ? right->as_avl()->height : 0;
  }

  inline void update_height() noexcept {
    height = std::max(lheight(), rheight()) + 1;
  }
};

struct RBNodeBase : public NodeBase {
  ColorType color;

  inline void set_marker() noexcept { as_red(); }
  inline bool is_marker() const noexcept { return is_red(); }

  inline bool is_red() const noexcept { return color == kColorRed; }
  inline bool is_blk() const noexcept { return color == kColorBlk; }
  inline void as_red() noexcept { color = kColorRed; }
  inline void as_blk() noexcept { color = kColorBlk; }
  inline void set_color(ColorType c) noexcept { color = c; }
};

template <typename Value> struct AVLNode : public AVLNodeBase {
  Value value;
};

template <typename Value> struct RBNode : public RBNodeBase {
  Value value;
};

template <typename _Tp, typename _Ref, typename _Ptr, typename _Node>
struct TreeIter {
  using Iter = TreeIter<_Tp, _Tp&, _Tp*, _Node>;
  using Self = TreeIter<_Tp, _Ref, _Ptr, _Node>;
  using Ref  = _Ref;
  using Ptr  = _Ptr;
  using Link = _Node*;

  BasePtr _node{};

  TreeIter() noexcept {}
  TreeIter(BasePtr x) noexcept : _node(x) {}
  TreeIter(ConstBasePtr x) noexcept : _node(const_cast<BasePtr>(x)) {}
  TreeIter(const Iter& x) noexcept : _node(x._node) {}

  inline void increment() noexcept { _node = NodeBase::successor(_node); }

  template <typename HeadChecker>
  inline void decrement(HeadChecker&& checker) noexcept {
    _node = NodeBase::predecessor(_node, std::move(checker));
  }

  inline Link node() const noexcept { return Link(_node); }
  inline Ref operator*() const noexcept { return Link(_node)->value; }
  inline Ptr operator->() const noexcept { return &Link(_node)->value; }

  inline bool operator==(const Self& r) const noexcept {
    return _node == r._node;
  }

  inline bool operator!=(const Self& r) const noexcept {
    return _node != r._node;
  }

  Self& operator++() noexcept { increment(); return *this; }
  Self operator++(int) noexcept { Self tmp(*this); increment(); return tmp; }

  Self& operator--() noexcept {
    decrement([](BasePtr x) { return Link(x)->is_marker(); });
    return *this;
  }

  Self operator--(int) noexcept {
    Self tmp(*this);
    decrement([](BasePtr x) { return Link(x)->is_marker(); });
    return tmp;
  }
};

template <typename Tp,
          typename Node,
          typename Less = std::less<Tp>,
          typename Equal = std::equal_to<Tp>>
class TreeBase : private UnCopyable {
public:
  using ValueType = Tp;
  using Iter      = TreeIter<Tp, Tp&, Tp*, Node>;
  using ConstIter = TreeIter<Tp, const Tp&, const Tp*, Node>;
  using Ref       = Tp&;
  using ConstRef  = const Tp&;
protected:
  using Link      = Node*;
  using ConstLink = const Node*;
  using Alloc     = wrencc::SimpleAlloc<Node>;

  sz_t size_{};
  Node head_{};
  Less lt_comp_{};
  Equal eq_comp_{};

  static inline Link _parent(BasePtr x) noexcept { return Link(x)->parent; }
  static inline ConstLink _parent(ConstBasePtr x) noexcept { return ConstLink(x)->parent; }
  static inline Link _left(BasePtr x) noexcept { return Link(x)->left; }
  static inline ConstLink _left(ConstBasePtr x) noexcept { return ConstLink(x)->left; }
  static inline Link _right(BasePtr x) noexcept { return Link(x)->right; }
  static inline ConstLink _right(ConstBasePtr x) noexcept { return ConstLink(x)->right; }

  inline void init() noexcept {
    size_ = 0;
    head_.parent = nullptr;
    head_.left = head_.right = &head_;
    head_.set_marker();
  }

  inline Link root() noexcept { return Link(head_.parent); }
  inline ConstLink root() const noexcept { return ConstLink(head_.parent); }
  inline Link tail() noexcept { return Link(&head_); }
  inline ConstLink tail() const noexcept { return ConstLink(&head_); }
  inline Link lmost() noexcept { return Link(head_.left); }
  inline ConstLink lmost() noexcept { return ConstLink(head_.left); }
  inline Link rmost() noexcept { return Link(head_.right); }
  inline ConstLink rmost() const noexcept { return ConstLink(head_.right); }

  inline Link get_node() noexcept { return Alloc::allocate(); }
  inline void put_node(Link p) noexcept { Alloc::deallocate(p); }
};

}
<commit_msg>:construction: chore(tree): updated tree framework<commit_after>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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.
#pragma once

#include <algorithm>
#include <tuple>
#include "helper.hh"

namespace wrencc::tree {

using ColorType = bool;
static constexpr ColorType kColorRed = false;
static constexpr ColorType kColorBlk = true;
static constexpr int kHeightMark = 0xff;

struct NodeBase;
struct AVLNodeBase;
struct RBNodeBase;
using BasePtr       = NodeBase*;
using ConstBasePtr  = const NodeBase*;

namespace impl::avl {
  void insert(bool insert_left, BasePtr x, BasePtr p, NodeBase& header) noexcept;
  void erase(BasePtr x, NodeBase& root) noexcept;
}

namespace impl::rb {
  void insert(bool insert_left, BasePtr x, BasePtr p, NodeBase& header) noexcept;
  void erase(BasePtr x, NodeBase& header) noexcept;
}

struct NodeBase {
  BasePtr parent;
  BasePtr left;
  BasePtr right;

  template <typename AVL = AVLNodeBase> inline AVL* as_avl() noexcept {
    return static_cast<AVL*>(this);
  }

  template <typename RB = AVLNodeBase> inline RB* as_rb() noexcept {
    return static_cast<RB*>(this);
  }

  static BasePtr successor(BasePtr x) noexcept {
    if (x->right != nullptr) {
      x = x->right;
      while (x->left != nullptr)
        x = x->left;
    }
    else {
      BasePtr y = x->parent;
      while (x == y->right) {
        x = y;
        y = y->parent;
      }
      if (x->right != y)
        x = y;
    }
    return x;
  }

  template <typename HeadChecker>
  static BasePtr predecessor(BasePtr x, HeadChecker&& checker) noexcept {
    if (checker(x) && x->parent->parent == x) {
      x = x->right;
    }
    else if (x->left != nullptr) {
      x = x->left;
      while (x->right != nullptr)
        x = x->right;
    }
    else {
      BasePtr y = x->parent;
      while (x == y->left) {
        x = y;
        y = y->parent;
      }
      x = y;
    }
    return x;
  }
};

struct AVLNodeBase : public NodeBase {
  int height;

  inline void set_marker() noexcept { height = kHeightMark; }
  inline bool is_marker() const noexcept { return height == kHeightMark; }
  inline void set_height(int h) noexcept { height = h; }

  inline int lheight() const noexcept {
    return left != nullptr ? left->as_avl()->height : 0;
  }

  inline int rheight() const noexcept {
    return right != nullptr ? right->as_avl()->height : 0;
  }

  inline void update_height() noexcept {
    height = std::max(lheight(), rheight()) + 1;
  }
};

struct RBNodeBase : public NodeBase {
  ColorType color;

  inline void set_marker() noexcept { as_red(); }
  inline bool is_marker() const noexcept { return is_red(); }

  inline bool is_red() const noexcept { return color == kColorRed; }
  inline bool is_blk() const noexcept { return color == kColorBlk; }
  inline void as_red() noexcept { color = kColorRed; }
  inline void as_blk() noexcept { color = kColorBlk; }
  inline void set_color(ColorType c) noexcept { color = c; }
};

template <typename Value> struct AVLNode : public AVLNodeBase {
  Value value;
};

template <typename Value> struct RBNode : public RBNodeBase {
  Value value;
};

template <typename _Tp, typename _Ref, typename _Ptr, typename _Node>
struct TreeIter {
  using Iter = TreeIter<_Tp, _Tp&, _Tp*, _Node>;
  using Self = TreeIter<_Tp, _Ref, _Ptr, _Node>;
  using Ref  = _Ref;
  using Ptr  = _Ptr;
  using Link = _Node*;

  BasePtr _node{};

  TreeIter() noexcept {}
  TreeIter(BasePtr x) noexcept : _node(x) {}
  TreeIter(ConstBasePtr x) noexcept : _node(const_cast<BasePtr>(x)) {}
  TreeIter(const Iter& x) noexcept : _node(x._node) {}

  inline void increment() noexcept { _node = NodeBase::successor(_node); }

  template <typename HeadChecker>
  inline void decrement(HeadChecker&& checker) noexcept {
    _node = NodeBase::predecessor(_node, std::move(checker));
  }

  inline Link node() const noexcept { return Link(_node); }
  inline Ref operator*() const noexcept { return Link(_node)->value; }
  inline Ptr operator->() const noexcept { return &Link(_node)->value; }

  inline bool operator==(const Self& r) const noexcept {
    return _node == r._node;
  }

  inline bool operator!=(const Self& r) const noexcept {
    return _node != r._node;
  }

  Self& operator++() noexcept { increment(); return *this; }
  Self operator++(int) noexcept { Self tmp(*this); increment(); return tmp; }

  Self& operator--() noexcept {
    decrement([](BasePtr x) { return Link(x)->is_marker(); });
    return *this;
  }

  Self operator--(int) noexcept {
    Self tmp(*this);
    decrement([](BasePtr x) { return Link(x)->is_marker(); });
    return tmp;
  }
};

template <typename Tp,
          typename Node,
          typename Less = std::less<Tp>,
          typename Equal = std::equal_to<Tp>>
class TreeBase : private UnCopyable {
public:
  using ValueType = Tp;
  using Iter      = TreeIter<Tp, Tp&, Tp*, Node>;
  using ConstIter = TreeIter<Tp, const Tp&, const Tp*, Node>;
  using Ref       = Tp&;
  using ConstRef  = const Tp&;
protected:
  using Link      = Node*;
  using ConstLink = const Node*;
  using Alloc     = wrencc::SimpleAlloc<Node>;

  sz_t size_{};
  Node head_{};
  Less lt_comp_{};
  Equal eq_comp_{};

  static inline Link _parent(BasePtr x) noexcept { return Link(x)->parent; }
  static inline ConstLink _parent(ConstBasePtr x) noexcept { return ConstLink(x)->parent; }
  static inline Link _left(BasePtr x) noexcept { return Link(x)->left; }
  static inline ConstLink _left(ConstBasePtr x) noexcept { return ConstLink(x)->left; }
  static inline Link _right(BasePtr x) noexcept { return Link(x)->right; }
  static inline ConstLink _right(ConstBasePtr x) noexcept { return ConstLink(x)->right; }

  inline void init() noexcept {
    size_ = 0;
    head_.parent = nullptr;
    head_.left = head_.right = &head_;
    head_.set_marker();
  }

  inline Link root() noexcept { return Link(head_.parent); }
  inline ConstLink root() const noexcept { return ConstLink(head_.parent); }
  inline Link tail() noexcept { return Link(&head_); }
  inline ConstLink tail() const noexcept { return ConstLink(&head_); }
  inline Link lmost() noexcept { return Link(head_.left); }
  inline ConstLink lmost() noexcept { return ConstLink(head_.left); }
  inline Link rmost() noexcept { return Link(head_.right); }
  inline ConstLink rmost() const noexcept { return ConstLink(head_.right); }

  inline Link get_node() noexcept { return Alloc::allocate(); }
  inline void put_node(Link p) noexcept { Alloc::deallocate(p); }

  Link create_node(const ValueType& val) {
    Link tmp = get_node();
    try {
      construct(&tmp->value, val);
    }
    catch (...) {
      put_node(tmp);
      throw;
    }
    return tmp;
  }

  Link create_node(ValueType&& val) {
    Link tmp = get_node();
    try {
      construct(&tmp->value, std::move(val));
    }
    catch (...) {
      put_node(tmp);
      throw;
    }
    return tmp;
  }

  template <typename... Args> Link create_node(Args&&... args) {
    Link tmp = get_node();
    try {
      construct(&tmp->value, std::forward<Args>(args)...);
    }
    catch (...) {
      put_node(tmp);
      throw;
    }
    return tmp;
  }

  void destroy_node(Link p) {
    destroy(&p->value);
    put_node(p);
  }

  inline std::tuple<bool, Link, bool> find_insertion_pos(const ValueType& key) {
    Link x = root();
    Link p = tail();
    while (x != nullptr) {
      if (eq_comp_(key, x->value))
        return std::make_tuple(false, nullptr, false);

      p = x;
      x = lt_comp_(key, x->value) ? _left(x) : _right(x);
    }
    bool insert_left = x != nullptr || p == tail() || lt_comp_(key, p->value);

    return std::make_tuple(true, p, insert_left);
  }

  template <typename Insertion>
  inline void insert_aux(Insertion&& insert_fn, const ValueType& value) {
    auto [r, p, insert_left] = find_insertion_pos(value);
    if (r) {
      insert_fn(insert_left, create_node(value), p, head_);
      ++size_;
    }
  }

  template <typename Insertion>
  inline void insert_aux(Insertion&& insert_fn, ValueType&& value) {
    auto [r, p, insert_left] = find_insertion_pos(value);
    if (r) {
      insert_fn(insert_left, create_node(std::move(value)), p, head_);
      ++size_;
    }
  }

  template <typename Insertion, typename... Args>
  inline void insert_aux(Insertion&& insert_fn, Args&&... args) {
    Link tmp = create_node(std::forward<Args>(args)...);
    auto [r, p, insert_left] = find_insertion_pos(tmp->value);
    if (r) {
      insert_fn(insert_left, tmp, p, head_);
      ++size_;
    }
    else {
      destroy_node(tmp);
    }
  }

  template <typename Eraser> inline void erase_aux(Eraser&& erase_fn, Link p) {
    if (size_ != 0) {
      erase_fn(p, head_);
      destroy_node(p);
      --size_;
    }
  }

  void erase_subtree(Link x) {
    while (x != nullptr) {
      erase_subtree(_right(x));
      Link y = _left(x);
      destroy_node(x);
      x = y;
    }
  }

  inline ConstLink find_aux(const ValueType& key) const noexcept {
    ConstLink x = root();
    ConstLink y = tail();
    while (x != nullptr) {
      if (eq_comp_(key, x->value)) {
        y = x;
        break;
      }
      x = lt_comp_(key, x->value) ? _left(x) : _right(x);
    }
    return y;
  }
public:
  TreeBase() noexcept { init(); }
  ~TreeBase() noexcept { clear(); }

  inline bool empty() const noexcept { return size_ == 0; }
  inline sz_t size() const noexcept { return size_; }
  inline Iter begin() noexcept { return head_.left; }
  inline ConstIter begin() const noexcept { return head_.left; }
  inline Iter end() noexcept { return &head_; }
  inline ConstIter end() const noexcept { return &head_; }
  inline Ref get_head() noexcept { return *begin(); }
  inline ConstRef get_head() const noexcept { return *begin(); }
  inline Ref get_tail() noexcept { return *(--end()); }
  inline ConstRef get_tail() const noexcept { return *(--end()); }

  inline void clear() {
    erase_subtree(root());
    init();
  }

  inline Iter find(const ValueType& key) noexcept {
    return find_aux(key);
  }

  inline ConstIter find(const ValueType& key) const noexcept {
    return find_aux(key);
  }

  template <typename Visitor> inline void for_each(Visitor&& visitor) {
    for (auto i = begin(); i != end(); ++i)
      visitor(*i);
  }
};

}

namespace wrencc {

template <typename Tp>
class AVLTree final : public tree::TreeBase<Tp, tree::AVLNode<Tp>> {
};

template <typename Tp>
class RBTree final : public tree::TreeBase<Tp, tree::RBNode<Tp>> {
};

}
<|endoftext|>


<commit_before>#include <utki/config.hpp>
#include <utki/types.hpp>

#if M_OS == M_OS_WINDOWS
#	include <utki/windows.hpp>

#elif M_OS == M_OS_LINUX || M_OS == M_OS_MACOSX
#	include <dirent.h>
#	include <sys/stat.h>
#	include <cerrno>
#	include <cstring>

#endif

#include <vector>
#include <cstdlib>
#include <sstream>

#include "FSFile.hpp"

using namespace papki;

void FSFile::openInternal(E_Mode mode){
	if(this->isDir()){
		throw papki::Exc("path refers to a directory, directories can't be opened");
	}

	const char* modeStr;
	switch(mode){
		case File::E_Mode::WRITE:
			modeStr = "r+b";
			break;
		case File::E_Mode::CREATE:
			modeStr = "w+b";
			break;
		case File::E_Mode::READ:
			modeStr = "rb";
			break;
		default:
			throw papki::Exc("unknown mode");
			break;
	}

#if M_COMPILER == M_COMPILER_MSVC
	if(fopen_s(&this->handle, this->path().c_str(), modeStr) != 0){
		this->handle = 0;
	}
#else
	this->handle = fopen(this->path().c_str(), modeStr);
#endif
	if(!this->handle){
		TRACE(<< "FSFile::Open(): Path() = " << this->path().c_str() << std::endl)
		std::stringstream ss;
		ss << "fopen(" << this->path().c_str() << ") failed";
		throw papki::Exc(ss.str());
	}
}

//override
void FSFile::closeInternal()const noexcept{
	ASSERT(this->handle)

	fclose(this->handle);
	this->handle = 0;
}

//override
size_t FSFile::readInternal(utki::Buf<std::uint8_t> buf)const{
	ASSERT(this->handle)
	size_t numBytesRead = fread(buf.begin(), 1, buf.size(), this->handle);
	if(numBytesRead != buf.size()){//something happened
		if(!feof(this->handle)){
			throw papki::Exc("fread() error");//if it is not an EndOfFile then it is error
		}
	}
	return numBytesRead;
}

//override
size_t FSFile::writeInternal(const utki::Buf<std::uint8_t> buf){
	ASSERT(this->handle)
	size_t bytesWritten = fwrite(buf.begin(), 1, buf.size(), this->handle);
	if(bytesWritten != buf.size()){//something bad has happened
		throw papki::Exc("fwrite error");
	}

	return bytesWritten;
}

size_t FSFile::seekBackwardInternal(size_t numBytesToSeek)const{
	ASSERT(this->handle)

	//NOTE: fseek() accepts 'long int' as offset argument which is signed and can be
	//      less than size_t value passed as argument to this function.
	//      Therefore, do several seek operations with smaller offset if necessary.

	typedef long int T_FSeekOffset;
	const std::size_t DMax = std::size_t(
			((unsigned long int)(-1)) >> 1
		);
	ASSERT((size_t(1) << ((sizeof(T_FSeekOffset) * 8) - 1)) - 1 == DMax)
	static_assert(size_t(-(-T_FSeekOffset(DMax))) == DMax, "error");

	utki::clampTop(numBytesToSeek, this->curPos());

	for(size_t numBytesLeft = numBytesToSeek; numBytesLeft != 0;){
		ASSERT(numBytesLeft <= numBytesToSeek)

		T_FSeekOffset offset;
		if(numBytesLeft > DMax){
			offset = T_FSeekOffset(DMax);
		}else{
			offset = T_FSeekOffset(numBytesLeft);
		}

		ASSERT(offset > 0)

		if(fseek(this->handle, -offset, SEEK_CUR) != 0){
			throw papki::Exc("fseek() failed");
		}

		ASSERT(size_t(offset) < size_t(-1))
		ASSERT(numBytesLeft >= size_t(offset))

		numBytesLeft -= size_t(offset);
	}

	return numBytesToSeek;
}

//override
void FSFile::rewindInternal()const{
	if(!this->isOpened()){
		throw papki::IllegalStateExc("cannot rewind, file is not opened");
	}

	ASSERT(this->handle)
	if(fseek(this->handle, 0, SEEK_SET) != 0){
		throw papki::Exc("fseek() failed");
	}
}

//override
bool FSFile::exists()const{
	if(this->isOpened()){ //file is opened => it exists
		return true;
	}

	if(this->path().size() == 0){
		return false;
	}

	//if it is a directory, check directory existence
	if(this->path()[this->path().size() - 1] == '/'){
#if M_OS == M_OS_LINUX
		DIR *pdir = opendir(this->path().c_str());
		if(!pdir){
			return false;
		}else{
			closedir(pdir);
			return true;
		}
#else
		throw papki::Exc("Checking for directory existence is not supported");
#endif
	}else{
		return this->File::exists();
	}
}

//override
void FSFile::makeDir(){
	if(this->isOpened()){
		throw papki::IllegalStateExc("cannot make directory when file is opened");
	}

	if(this->path().size() == 0 || this->path()[this->path().size() - 1] != '/'){
		throw papki::Exc("invalid directory name");
	}

#if M_OS == M_OS_LINUX
//	TRACE(<< "creating directory = " << this->Path() << std::endl)
	umask(0);//clear umask for proper permissions of newly created directory
	if(mkdir(this->path().c_str(), 0777) != 0){
		throw papki::Exc("mkdir() failed");
	}
#else
	throw papki::Exc("creating directory is not supported");
#endif
}

std::string FSFile::getHomeDir() {
	std::string ret;

#if M_OS == M_OS_WINDOWS && M_COMPILER == M_COMPILER_MSVC
	{
		char* buf = nullptr;
		size_t size = 0;

		utki::ScopeExit scopeExit([&buf](){
			free(buf);
		});

		if (_dupenv_s(&buf, &size, "USERPROFILE") != 0) {
			throw papki::Exc("USERPROFILE  environment virable could not be read");
		}
		ret = std::string(buf);
	}
#elif M_OS == M_OS_LINUX || M_OS == M_OS_WINDOWS || M_OS == M_OS_MACOSX

#	if M_OS == M_OS_LINUX || M_OS == M_OS_MACOSX
	char * home = getenv("HOME");
#	elif M_OS == M_OS_WINDOWS
	char * home = getenv("USERPROFILE");
#	else
#		error "unsupported OS"
#	endif

	if(!home){
		throw papki::Exc("HOME environment variable does not exist");
	}

	ret = std::string(home);
#else
#	error "unsupported os"
#endif

	//append trailing '/' if needed
	if(ret.size() == 0 || ret[ret.size() - 1] != '/'){
		ret += '/';
	}

	return ret;
}

std::vector<std::string> FSFile::listDirContents(size_t maxEntries)const{
	if(!this->isDir()){
		throw papki::Exc("FSFile::ListDirContents(): this is not a directory");
	}

	std::vector<std::string> files;

#if M_OS == M_OS_WINDOWS
	{
		std::string pattern = this->path();
		pattern += '*';

		TRACE(<< "FSFile::ListDirContents(): pattern = " << pattern << std::endl)

		WIN32_FIND_DATA wfd;
		HANDLE h = FindFirstFile(pattern.c_str(), &wfd);
		if (h == INVALID_HANDLE_VALUE) {
			throw papki::Exc("ListDirContents(): cannot find first file");
		}

		//create Find Closer to automatically call FindClose on exit from the function in case of exceptions etc...
		{
			utki::ScopeExit scopeExit([h]() {
				FindClose(h);
			});

			do {
				std::string s(wfd.cFileName);
				ASSERT(s.size() > 0)

				//do not add ./ and ../ directories, we are not interested in them
				if (s == "." || s == "..") {
					continue;
				}

				if (((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && s[s.size() - 1] != '/') {
					s += '/';
				}
				files.push_back(s);

				if (files.size() == maxEntries) {
					break;
				}
			} while (FindNextFile(h, &wfd) != 0);

			if (GetLastError() != ERROR_SUCCESS && GetLastError() != ERROR_NO_MORE_FILES) {
				throw papki::Exc("ListDirContents(): find next file failed");
			}
		}
	}
#elif M_OS == M_OS_LINUX || M_OS == M_OS_MACOSX
	{
		DIR *pdir = opendir(this->path().c_str());

		if(!pdir){
			std::stringstream ss;
			ss << "FSFile::ListDirContents(): opendir() failure, error code = " << strerror(errno);
			throw papki::Exc(ss.str());
		}

		//create DirentCloser to automatically call closedir on exit from the function in case of exceptions etc...
		struct DirCloser{
			DIR *pdir;

			DirCloser(DIR *pDirToClose) :
					pdir(pDirToClose)
			{}

			~DirCloser(){
				int ret;
				do{
					ret = closedir(this->pdir);
					ASSERT_INFO(ret == 0 || errno == EINTR, "FSFile::ListDirContents(): closedir() failed: " << strerror(errno))
				}while(ret != 0 && errno == EINTR);
			}
		} dirCloser(pdir);

		errno = 0;//clear errno
		while(dirent *pent = readdir(pdir)){
			std::string s(pent->d_name);
			if(s == "." || s == "..")
				continue;//do not add ./ and ../ directories, we are not interested in them

			struct stat fileStats;
			//TRACE(<< s << std::endl)
			if(stat((this->path() + s).c_str(), &fileStats) < 0){
				std::stringstream ss;
				ss << "FSFile::ListDirContents(): stat() failure, error code = " << strerror(errno);
				throw papki::Exc(ss.str());
			}

			if(fileStats.st_mode & S_IFDIR)//if this entry is a directory append '/' symbol to its end
				s += "/";

			files.push_back(s);

			if(files.size() == maxEntries){
				break;
			}
		}//~while()

		//check if we exited the while() loop because of readdir() failed
		if(errno != 0){
			std::stringstream ss;
			ss << "FSFile::ListDirContents(): readdir() failure, error code = " << strerror(errno);
			throw papki::Exc(ss.str());
		}
	}

#else

#	error "FSFile::ListDirContents(): version is not implemented yet for this os"

#endif
	return files;
}

std::unique_ptr<File> FSFile::spawn(){
	return utki::makeUnique<FSFile>();
}
<commit_msg>implemented directory creation under windows<commit_after>#include <utki/config.hpp>
#include <utki/types.hpp>

#if M_OS == M_OS_WINDOWS
#	include <utki/windows.hpp>

#elif M_OS == M_OS_LINUX || M_OS == M_OS_MACOSX
#	include <dirent.h>
#	include <sys/stat.h>
#	include <cerrno>
#	include <cstring>

#endif

#include <vector>
#include <cstdlib>
#include <sstream>

#include "FSFile.hpp"

using namespace papki;

void FSFile::openInternal(E_Mode mode){
	if(this->isDir()){
		throw papki::Exc("path refers to a directory, directories can't be opened");
	}

	const char* modeStr;
	switch(mode){
		case File::E_Mode::WRITE:
			modeStr = "r+b";
			break;
		case File::E_Mode::CREATE:
			modeStr = "w+b";
			break;
		case File::E_Mode::READ:
			modeStr = "rb";
			break;
		default:
			throw papki::Exc("unknown mode");
			break;
	}

#if M_COMPILER == M_COMPILER_MSVC
	if(fopen_s(&this->handle, this->path().c_str(), modeStr) != 0){
		this->handle = 0;
	}
#else
	this->handle = fopen(this->path().c_str(), modeStr);
#endif
	if(!this->handle){
		TRACE(<< "FSFile::Open(): Path() = " << this->path().c_str() << std::endl)
		std::stringstream ss;
		ss << "fopen(" << this->path().c_str() << ") failed";
		throw papki::Exc(ss.str());
	}
}

//override
void FSFile::closeInternal()const noexcept{
	ASSERT(this->handle)

	fclose(this->handle);
	this->handle = 0;
}

//override
size_t FSFile::readInternal(utki::Buf<std::uint8_t> buf)const{
	ASSERT(this->handle)
	size_t numBytesRead = fread(buf.begin(), 1, buf.size(), this->handle);
	if(numBytesRead != buf.size()){//something happened
		if(!feof(this->handle)){
			throw papki::Exc("fread() error");//if it is not an EndOfFile then it is error
		}
	}
	return numBytesRead;
}

//override
size_t FSFile::writeInternal(const utki::Buf<std::uint8_t> buf){
	ASSERT(this->handle)
	size_t bytesWritten = fwrite(buf.begin(), 1, buf.size(), this->handle);
	if(bytesWritten != buf.size()){//something bad has happened
		throw papki::Exc("fwrite error");
	}

	return bytesWritten;
}

size_t FSFile::seekBackwardInternal(size_t numBytesToSeek)const{
	ASSERT(this->handle)

	//NOTE: fseek() accepts 'long int' as offset argument which is signed and can be
	//      less than size_t value passed as argument to this function.
	//      Therefore, do several seek operations with smaller offset if necessary.

	typedef long int T_FSeekOffset;
	const std::size_t DMax = std::size_t(
			((unsigned long int)(-1)) >> 1
		);
	ASSERT((size_t(1) << ((sizeof(T_FSeekOffset) * 8) - 1)) - 1 == DMax)
	static_assert(size_t(-(-T_FSeekOffset(DMax))) == DMax, "error");

	utki::clampTop(numBytesToSeek, this->curPos());

	for(size_t numBytesLeft = numBytesToSeek; numBytesLeft != 0;){
		ASSERT(numBytesLeft <= numBytesToSeek)

		T_FSeekOffset offset;
		if(numBytesLeft > DMax){
			offset = T_FSeekOffset(DMax);
		}else{
			offset = T_FSeekOffset(numBytesLeft);
		}

		ASSERT(offset > 0)

		if(fseek(this->handle, -offset, SEEK_CUR) != 0){
			throw papki::Exc("fseek() failed");
		}

		ASSERT(size_t(offset) < size_t(-1))
		ASSERT(numBytesLeft >= size_t(offset))

		numBytesLeft -= size_t(offset);
	}

	return numBytesToSeek;
}

//override
void FSFile::rewindInternal()const{
	if(!this->isOpened()){
		throw papki::IllegalStateExc("cannot rewind, file is not opened");
	}

	ASSERT(this->handle)
	if(fseek(this->handle, 0, SEEK_SET) != 0){
		throw papki::Exc("fseek() failed");
	}
}

//override
bool FSFile::exists()const{
	if(this->isOpened()){ //file is opened => it exists
		return true;
	}

	if(this->path().size() == 0){
		return false;
	}

	//if it is a directory, check directory existence
	if(this->path()[this->path().size() - 1] == '/'){
#if M_OS == M_OS_LINUX
		DIR *pdir = opendir(this->path().c_str());
		if(!pdir){
			return false;
		}else{
			closedir(pdir);
			return true;
		}
#else
		throw papki::Exc("Checking for directory existence is not supported");
#endif
	}else{
		return this->File::exists();
	}
}

//override
void FSFile::makeDir(){
	if(this->isOpened()){
		throw papki::IllegalStateExc("cannot make directory when file is opened");
	}

	if(this->path().size() == 0 || this->path()[this->path().size() - 1] != '/'){
		throw papki::Exc("invalid directory name");
	}

#if M_OS == M_OS_LINUX
//	TRACE(<< "creating directory = " << this->Path() << std::endl)
	umask(0);//clear umask for proper permissions of newly created directory
	if(mkdir(this->path().c_str(), 0777) != 0){
		throw papki::Exc("mkdir() failed");
	}
#elif M_OS == M_OS_WINDOWS
	if (!CreateDirectory(this->path().c_str(), NULL)){
		if(GetLastError() != ERROR_ALREADY_EXISTS){
			throw papki::Exc("CreateDirectory() failed");
		}
	}
#else
	throw papki::Exc("creating directory is not supported");
#endif
}

std::string FSFile::getHomeDir() {
	std::string ret;

#if M_OS == M_OS_WINDOWS && M_COMPILER == M_COMPILER_MSVC
	{
		char* buf = nullptr;
		size_t size = 0;

		utki::ScopeExit scopeExit([&buf](){
			free(buf);
		});

		if (_dupenv_s(&buf, &size, "USERPROFILE") != 0) {
			throw papki::Exc("USERPROFILE  environment virable could not be read");
		}
		ret = std::string(buf);
	}
#elif M_OS == M_OS_LINUX || M_OS == M_OS_WINDOWS || M_OS == M_OS_MACOSX

#	if M_OS == M_OS_LINUX || M_OS == M_OS_MACOSX
	char * home = getenv("HOME");
#	elif M_OS == M_OS_WINDOWS
	char * home = getenv("USERPROFILE");
#	else
#		error "unsupported OS"
#	endif

	if(!home){
		throw papki::Exc("HOME environment variable does not exist");
	}

	ret = std::string(home);
#else
#	error "unsupported os"
#endif

	//append trailing '/' if needed
	if(ret.size() == 0 || ret[ret.size() - 1] != '/'){
		ret += '/';
	}

	return ret;
}

std::vector<std::string> FSFile::listDirContents(size_t maxEntries)const{
	if(!this->isDir()){
		throw papki::Exc("FSFile::ListDirContents(): this is not a directory");
	}

	std::vector<std::string> files;

#if M_OS == M_OS_WINDOWS
	{
		std::string pattern = this->path();
		pattern += '*';

		TRACE(<< "FSFile::ListDirContents(): pattern = " << pattern << std::endl)

		WIN32_FIND_DATA wfd;
		HANDLE h = FindFirstFile(pattern.c_str(), &wfd);
		if (h == INVALID_HANDLE_VALUE) {
			throw papki::Exc("ListDirContents(): cannot find first file");
		}

		//create Find Closer to automatically call FindClose on exit from the function in case of exceptions etc...
		{
			utki::ScopeExit scopeExit([h]() {
				FindClose(h);
			});

			do {
				std::string s(wfd.cFileName);
				ASSERT(s.size() > 0)

				//do not add ./ and ../ directories, we are not interested in them
				if (s == "." || s == "..") {
					continue;
				}

				if (((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && s[s.size() - 1] != '/') {
					s += '/';
				}
				files.push_back(s);

				if (files.size() == maxEntries) {
					break;
				}
			} while (FindNextFile(h, &wfd) != 0);

			if (GetLastError() != ERROR_SUCCESS && GetLastError() != ERROR_NO_MORE_FILES) {
				throw papki::Exc("ListDirContents(): find next file failed");
			}
		}
	}
#elif M_OS == M_OS_LINUX || M_OS == M_OS_MACOSX
	{
		DIR *pdir = opendir(this->path().c_str());

		if(!pdir){
			std::stringstream ss;
			ss << "FSFile::ListDirContents(): opendir() failure, error code = " << strerror(errno);
			throw papki::Exc(ss.str());
		}

		//create DirentCloser to automatically call closedir on exit from the function in case of exceptions etc...
		struct DirCloser{
			DIR *pdir;

			DirCloser(DIR *pDirToClose) :
					pdir(pDirToClose)
			{}

			~DirCloser(){
				int ret;
				do{
					ret = closedir(this->pdir);
					ASSERT_INFO(ret == 0 || errno == EINTR, "FSFile::ListDirContents(): closedir() failed: " << strerror(errno))
				}while(ret != 0 && errno == EINTR);
			}
		} dirCloser(pdir);

		errno = 0;//clear errno
		while(dirent *pent = readdir(pdir)){
			std::string s(pent->d_name);
			if(s == "." || s == "..")
				continue;//do not add ./ and ../ directories, we are not interested in them

			struct stat fileStats;
			//TRACE(<< s << std::endl)
			if(stat((this->path() + s).c_str(), &fileStats) < 0){
				std::stringstream ss;
				ss << "FSFile::ListDirContents(): stat() failure, error code = " << strerror(errno);
				throw papki::Exc(ss.str());
			}

			if(fileStats.st_mode & S_IFDIR)//if this entry is a directory append '/' symbol to its end
				s += "/";

			files.push_back(s);

			if(files.size() == maxEntries){
				break;
			}
		}//~while()

		//check if we exited the while() loop because of readdir() failed
		if(errno != 0){
			std::stringstream ss;
			ss << "FSFile::ListDirContents(): readdir() failure, error code = " << strerror(errno);
			throw papki::Exc(ss.str());
		}
	}

#else

#	error "FSFile::ListDirContents(): version is not implemented yet for this os"

#endif
	return files;
}

std::unique_ptr<File> FSFile::spawn(){
	return utki::makeUnique<FSFile>();
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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.
#pragma once

#include <functional>
#include <vector>
#include "common.hh"
#include "parser.hh"

namespace tadpole {

enum class FunType {
  FUNCTION,
  TOPLEVEL,
};

class FunctionObject;

class FunCompiler final : private UnCopyable {
  using ErrorFn = std::function<void (const str_t&)>;

  FunCompiler* enclosing_{};
  FunctionObject* fn_{};
  FunType fn_type_{};

  int scope_depth_{};

  std::vector<LocalVar> locals_;
  std::vector<Upvalue> upvalues_;
public:
  FunCompiler() noexcept {}

  FunCompiler(FunCompiler* enclosing,
      FunctionObject* fn, FunType fn_type, int scope_depth = 0) noexcept
    : enclosing_(enclosing), fn_(fn), fn_type_(fn_type), scope_depth_(scope_depth) {
  }

  inline void set_compiler(FunCompiler* enclosing,
      FunctionObject* fn, FunType fn_type, int scope_depth = 0) noexcept {
    enclosing_ = enclosing;
    fn_ = fn;
    fn_type_ = fn_type;
    scope_depth_ = scope_depth;
  }

  inline FunCompiler* enclosing() const noexcept { return enclosing_;}
  inline FunctionObject* fn() const noexcept { return fn_; }
  inline FunType fn_type() const noexcept { return fn_type_; }
  inline int scope_depth() const noexcept { return scope_depth_; }
  inline void set_scope_depth(int depth) noexcept { scope_depth_ = depth; }
  inline int locals_count() const noexcept { return as_type<int>(locals_.size()); }
  inline LocalVar& get_local(sz_t i) noexcept { return locals_[i]; }
  inline const LocalVar& get_local(sz_t i) const noexcept { return locals_[i]; }
  inline LocalVar& peek_local() noexcept { return locals_.back(); }
  inline const LocalVar& peek_local() const noexcept { return locals_.back(); }
  inline void append_local(const LocalVar& var) noexcept { locals_.push_back(var); }
  inline Upvalue& get_upvalue(sz_t i) noexcept { return upvalues_[i]; }
  inline const Upvalue& get_upvalue(sz_t i) const noexcept { return upvalues_[i]; }
  inline void append_upvalue(const Upvalue& u) noexcept { upvalues_.push_back(u); }

  void enter_scope() noexcept { ++scope_depth_; }
  template <typename Fn> void leave_scope(Fn&& visitor) {
    --scope_depth_;
    while (!locals_.empty() && peek_local().depth > scope_depth_) {
      visitor(peek_local());
      locals_.pop_back();
    }
  }

  int resolve_local(const Token& name, const ErrorFn& errfn);
  int add_upvalue(u8_t index, bool is_local);
  int resolve_upvalue(const Token& name, const ErrorFn& errfn);
  void declare_localvar(const Token& name, const ErrorFn& errfn);
};

}
<commit_msg>:construction: chore(fun-compiler): updated the implementation of function compiler<commit_after>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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.
#pragma once

#include <functional>
#include <vector>
#include "common.hh"
#include "compiler_internal.hh"

namespace tadpole {

enum class FunType {
  FUNCTION,
  TOPLEVEL,
};

class FunctionObject;

class FunCompiler final : private UnCopyable {
  using ErrorFn = std::function<void (const str_t&)>;

  FunCompiler* enclosing_{};
  FunctionObject* fn_{};
  FunType fn_type_{};

  int scope_depth_{};

  std::vector<LocalVar> locals_;
  std::vector<Upvalue> upvalues_;
public:
  FunCompiler() noexcept {}

  FunCompiler(FunCompiler* enclosing,
      FunctionObject* fn, FunType fn_type, int scope_depth = 0) noexcept
    : enclosing_(enclosing), fn_(fn), fn_type_(fn_type), scope_depth_(scope_depth) {
  }

  inline void set_compiler(FunCompiler* enclosing,
      FunctionObject* fn, FunType fn_type, int scope_depth = 0) noexcept {
    enclosing_ = enclosing;
    fn_ = fn;
    fn_type_ = fn_type;
    scope_depth_ = scope_depth;
  }

  inline FunCompiler* enclosing() const noexcept { return enclosing_;}
  inline FunctionObject* fn() const noexcept { return fn_; }
  inline FunType fn_type() const noexcept { return fn_type_; }
  inline int scope_depth() const noexcept { return scope_depth_; }
  inline void set_scope_depth(int depth) noexcept { scope_depth_ = depth; }
  inline int locals_count() const noexcept { return as_type<int>(locals_.size()); }
  inline LocalVar& get_local(sz_t i) noexcept { return locals_[i]; }
  inline const LocalVar& get_local(sz_t i) const noexcept { return locals_[i]; }
  inline LocalVar& peek_local() noexcept { return locals_.back(); }
  inline const LocalVar& peek_local() const noexcept { return locals_.back(); }
  inline void append_local(const LocalVar& var) noexcept { locals_.push_back(var); }
  inline Upvalue& get_upvalue(sz_t i) noexcept { return upvalues_[i]; }
  inline const Upvalue& get_upvalue(sz_t i) const noexcept { return upvalues_[i]; }
  inline void append_upvalue(const Upvalue& u) noexcept { upvalues_.push_back(u); }

  void enter_scope() noexcept { ++scope_depth_; }
  template <typename Fn> void leave_scope(Fn&& visitor) {
    --scope_depth_;
    while (!locals_.empty() && peek_local().depth > scope_depth_) {
      visitor(peek_local());
      locals_.pop_back();
    }
  }

  int resolve_local(const Token& name, const ErrorFn& errfn);
  int add_upvalue(u8_t index, bool is_local);
  int resolve_upvalue(const Token& name, const ErrorFn& errfn);
  void declare_localvar(const Token& name, const ErrorFn& errfn);
};

}
<|endoftext|>


<commit_before><commit_msg>Wrapping lines during presentation.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2019 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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 "lexer.hh"
#include "interpret_parser.hh"
#include "interpret_resolver.hh"
#include "interpret_interpreter.hh"
#include "interpret_loxcc.hh"

namespace loxcc::interpret {

Loxcc::Loxcc(void) noexcept
  : err_report_()
  , interp_(new Interpreter(err_report_)) {
}

void Loxcc::eval_impl(const str_t& source_bytes) {
  Lexer lex(source_bytes);
  Parser p(err_report_, lex);

  auto stmts = p.parse();
  if (err_report_.had_error())
    std::exit(-1);

  auto resolver = std::make_shared<Resolver>(err_report_, interp_);
  resolver->invoke_resolve(stmts);
  if (err_report_.had_error())
    std::exit(-2);

  interp_->interpret(stmts);
  if (err_report_.had_error())
    std::exit(-3);
}

}
<commit_msg>:construction: chore(loxcc): updated the loxcc implementation for interpreter<commit_after>// Copyright (c) 2019 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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 "interpret_interpreter.hh"
#include "interpret_loxcc.hh"

namespace loxcc::interpret {

Loxcc::Loxcc(void) noexcept
  : err_report_()
  , interp_(new Interpreter(err_report_)) {
}

void Loxcc::eval_impl(const str_t& source_bytes) {
  interp_->interpret(source_bytes);
}

}
<|endoftext|>


<commit_before>#include "any_value.hpp"

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstring>  // std::memcmp, std::strcmp, std::strlen, std::strncmp
#include <iostream> // std::cout, std::cin, std::cerr
#include <string>   // std::string
#include <stdint.h> // uint32_t etc.

namespace model
{
    class World;
}

namespace datatypes
{
    void AnyValue::set_default_values()
    {
        this->type = datatypes::UNKNOWN;
        this->bool_value = false;
        this->float_value = NAN;
        this->double_value = NAN;
        this->int32_t_value = 0;
        this->uint32_t_value = 0;
        this->void_pointer = nullptr;
        this->world_pointer = nullptr;
    }

    AnyValue::AnyValue()
    {
        // constructor.
        std::cout << "creating AnyValue unknown value.\n";
        this->set_default_values();
    }

    AnyValue::AnyValue(bool bool_value)
    {
        // constructor.
        std::cout << "creating AnyValue with bool value.\n";
        this->set_default_values();
        this->type = datatypes::BOOL;
        this->bool_value = bool_value;
    }

    AnyValue::AnyValue(std::string type, bool bool_value)
    {
        // constructor.
        std::cout << "creating AnyValue with bool value.\n";
        this->set_default_values();

        if (std::strcmp(type.c_str(), "bool"))
        {
            this->type = datatypes::BOOL;
            this->bool_value = bool_value;
        }
    }

    AnyValue::AnyValue(float float_value)
    {
        // constructor.
        std::cout << "creating AnyValue with float value.\n";
        this->set_default_values();
        this->type = datatypes::FLOAT;
        this->float_value = float_value;
    }

    AnyValue::AnyValue(std::string type, float float_value)
    {
        // constructor.
        std::cout << "creating AnyValue with float value.\n";
        this->set_default_values();

        if (std::strcmp(type.c_str(), "float"))
        {
            this->type = datatypes::FLOAT;
            this->float_value = float_value;
        }
    }

    AnyValue::AnyValue(double double_value)
    {
        // constructor.
        std::cout << "creating AnyValue with double value.\n";
        this->set_default_values();
        this->type = datatypes::DOUBLE;
        this->double_value = double_value;
    }

    AnyValue::AnyValue(std::string type, double double_value)
    {
        // constructor.
        std::cout << "creating AnyValue with double value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "double"))
        {
            this->type = datatypes::DOUBLE;
            this->double_value = double_value;
        }
    }

    AnyValue::AnyValue(int32_t int32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with int32_t value.\n";
        this->set_default_values();
        this->type = datatypes::INT32_T;
        this->int32_t_value = int32_t_value;
    }

    AnyValue::AnyValue(std::string type, int32_t int32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with int32_t value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "int32_t"))
        {
            this->type = datatypes::INT32_T;
            this->int32_t_value = int32_t_value;
        }
    }

    AnyValue::AnyValue(uint32_t uint32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with uint32_t value.\n";
        this->set_default_values();
        this->type = datatypes::UINT32_T;
        this->uint32_t_value = uint32_t_value;
    }

    AnyValue::AnyValue(std::string type, uint32_t uint32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with uint32_t value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "uint32_t"))
        {
            this->type = datatypes::UINT32_T;
            this->uint32_t_value = uint32_t_value;
        }
    }

    AnyValue::AnyValue(void* void_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with void* value.\n";
        this->set_default_values();
        this->type = datatypes::VOID_POINTER;
        this->void_pointer = void_pointer;
    }

    AnyValue::AnyValue(std::string type, void* void_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with void* value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "void*"))
        {
            this->type = datatypes::VOID_POINTER;
            this->void_pointer = void_pointer;
        }
    }

    AnyValue::AnyValue(model::World* world_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with model::World* value.\n";
        this->set_default_values();
        this->type = datatypes::WORLD_POINTER;
        this->world_pointer = world_pointer;
    }

    AnyValue::AnyValue(std::string type, model::World* world_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with model::World* value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "model::World*"))
        {
            this->type = datatypes::WORLD_POINTER;
            this->world_pointer = world_pointer;
        }
    }
}
<commit_msg>Edited `std::cout` output.<commit_after>#include "any_value.hpp"

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstring>  // std::memcmp, std::strcmp, std::strlen, std::strncmp
#include <iostream> // std::cout, std::cin, std::cerr
#include <string>   // std::string
#include <stdint.h> // uint32_t etc.

namespace model
{
    class World;
}

namespace datatypes
{
    void AnyValue::set_default_values()
    {
        this->type = datatypes::UNKNOWN;
        this->bool_value = false;
        this->float_value = NAN;
        this->double_value = NAN;
        this->int32_t_value = 0;
        this->uint32_t_value = 0;
        this->void_pointer = nullptr;
        this->world_pointer = nullptr;
    }

    AnyValue::AnyValue()
    {
        // constructor.
        std::cout << "creating AnyValue with unknown value.\n";
        this->set_default_values();
    }

    AnyValue::AnyValue(bool bool_value)
    {
        // constructor.
        std::cout << "creating AnyValue with bool value.\n";
        this->set_default_values();
        this->type = datatypes::BOOL;
        this->bool_value = bool_value;
    }

    AnyValue::AnyValue(std::string type, bool bool_value)
    {
        // constructor.
        std::cout << "creating AnyValue with bool value.\n";
        this->set_default_values();

        if (std::strcmp(type.c_str(), "bool"))
        {
            this->type = datatypes::BOOL;
            this->bool_value = bool_value;
        }
    }

    AnyValue::AnyValue(float float_value)
    {
        // constructor.
        std::cout << "creating AnyValue with float value.\n";
        this->set_default_values();
        this->type = datatypes::FLOAT;
        this->float_value = float_value;
    }

    AnyValue::AnyValue(std::string type, float float_value)
    {
        // constructor.
        std::cout << "creating AnyValue with float value.\n";
        this->set_default_values();

        if (std::strcmp(type.c_str(), "float"))
        {
            this->type = datatypes::FLOAT;
            this->float_value = float_value;
        }
    }

    AnyValue::AnyValue(double double_value)
    {
        // constructor.
        std::cout << "creating AnyValue with double value.\n";
        this->set_default_values();
        this->type = datatypes::DOUBLE;
        this->double_value = double_value;
    }

    AnyValue::AnyValue(std::string type, double double_value)
    {
        // constructor.
        std::cout << "creating AnyValue with double value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "double"))
        {
            this->type = datatypes::DOUBLE;
            this->double_value = double_value;
        }
    }

    AnyValue::AnyValue(int32_t int32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with int32_t value.\n";
        this->set_default_values();
        this->type = datatypes::INT32_T;
        this->int32_t_value = int32_t_value;
    }

    AnyValue::AnyValue(std::string type, int32_t int32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with int32_t value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "int32_t"))
        {
            this->type = datatypes::INT32_T;
            this->int32_t_value = int32_t_value;
        }
    }

    AnyValue::AnyValue(uint32_t uint32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with uint32_t value.\n";
        this->set_default_values();
        this->type = datatypes::UINT32_T;
        this->uint32_t_value = uint32_t_value;
    }

    AnyValue::AnyValue(std::string type, uint32_t uint32_t_value)
    {
        // constructor.
        std::cout << "creating AnyValue with uint32_t value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "uint32_t"))
        {
            this->type = datatypes::UINT32_T;
            this->uint32_t_value = uint32_t_value;
        }
    }

    AnyValue::AnyValue(void* void_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with void* value.\n";
        this->set_default_values();
        this->type = datatypes::VOID_POINTER;
        this->void_pointer = void_pointer;
    }

    AnyValue::AnyValue(std::string type, void* void_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with void* value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "void*"))
        {
            this->type = datatypes::VOID_POINTER;
            this->void_pointer = void_pointer;
        }
    }

    AnyValue::AnyValue(model::World* world_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with model::World* value.\n";
        this->set_default_values();
        this->type = datatypes::WORLD_POINTER;
        this->world_pointer = world_pointer;
    }

    AnyValue::AnyValue(std::string type, model::World* world_pointer)
    {
        // constructor.
        std::cout << "creating AnyValue with model::World* value.\n";
        this->set_default_values();
        if (std::strcmp(type.c_str(), "model::World*"))
        {
            this->type = datatypes::WORLD_POINTER;
            this->world_pointer = world_pointer;
        }
    }
}
<|endoftext|>


<commit_before>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <RunSpecParse.h>
#include <fstream>
#include <string>

RunSpecParse::RunSpecParse(std::string filename) : jsonfile(filename) {}

  std::vector<RunSpec *> &RunSpecParse::getruns(std::string runspec,
                                              std::string basedir,
                                              std::string outputdir,
                                              int start,
                                              int end) {

  std::ifstream t(jsonfile);
  std::string str((std::istreambuf_iterator<char>(t)),
                  std::istreambuf_iterator<char>());

  if (basedir.back() != '/') {
    basedir += '/';
  }

  if (outputdir.back() != '/') {
    outputdir += '/';
  }

  if (!reader.parse(str, root, 0)) {
    printf("error: file \"%s\" is not valid json\n", jsonfile.c_str());
    exit(1);
  }

  const Json::Value plugins = root[runspec];

  /** Run through all runs for the selected runspec group */
  for (unsigned int index = 0; index < plugins.size(); index++) {
    auto runid = plugins[index][ID].asInt();
    if ((runid >= start && runid <= end) || start == 0) {

      auto dir = basedir + plugins[index][DIR].asString();
      auto pre = plugins[index][PREFIX].asString();
      auto pos = plugins[index][POSTFIX].asString();
      auto start = plugins[index][START].asInt();
      auto end = plugins[index][END].asInt();

      /** If threshold is specified, use it. Else use default threshold alg. */
      int thresh = -1;
      auto object = plugins[index][THRESHOLD];
      if (object != Json::Value::null) {
        thresh = plugins[index][THRESHOLD].asInt();
      }

      // Make unique filename from runspec and runid
      std::ostringstream seqno;
      seqno.width(2);
      seqno << std::setfill('0') << runid;
      std::string outputfile = outputdir + runspec + "_" + seqno.str();

      runs.push_back(new RunSpec(dir, pre, pos, start, end, outputfile, thresh));
    }
  }
  return runs;
}
<commit_msg>missing #include not a problem locally but on Jenkins<commit_after>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <RunSpecParse.h>
#include <iomanip>
#include <fstream>
#include <string>

RunSpecParse::RunSpecParse(std::string filename) : jsonfile(filename) {}

  std::vector<RunSpec *> &RunSpecParse::getruns(std::string runspec,
                                              std::string basedir,
                                              std::string outputdir,
                                              int start,
                                              int end) {

  std::ifstream t(jsonfile);
  std::string str((std::istreambuf_iterator<char>(t)),
                  std::istreambuf_iterator<char>());

  if (basedir.back() != '/') {
    basedir += '/';
  }

  if (outputdir.back() != '/') {
    outputdir += '/';
  }

  if (!reader.parse(str, root, 0)) {
    printf("error: file \"%s\" is not valid json\n", jsonfile.c_str());
    exit(1);
  }

  const Json::Value plugins = root[runspec];

  /** Run through all runs for the selected runspec group */
  for (unsigned int index = 0; index < plugins.size(); index++) {
    auto runid = plugins[index][ID].asInt();
    if ((runid >= start && runid <= end) || start == 0) {

      auto dir = basedir + plugins[index][DIR].asString();
      auto pre = plugins[index][PREFIX].asString();
      auto pos = plugins[index][POSTFIX].asString();
      auto start = plugins[index][START].asInt();
      auto end = plugins[index][END].asInt();

      /** If threshold is specified, use it. Else use default threshold alg. */
      int thresh = -1;
      auto object = plugins[index][THRESHOLD];
      if (object != Json::Value::null) {
        thresh = plugins[index][THRESHOLD].asInt();
      }

      // Make unique filename from runspec and runid
      std::ostringstream seqno;
      seqno.width(2);
      seqno << std::setfill('0') << runid;
      std::string outputfile = outputdir + runspec + "_" + seqno.str();

      runs.push_back(new RunSpec(dir, pre, pos, start, end, outputfile, thresh));
    }
  }
  return runs;
}
<|endoftext|>