<commit_before>/*******************************************************************************
 * c7a/api/dia.hpp
 *
 * Interface for Operations, holds pointer to node and lambda from node to state
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_API_DIA_HEADER
#define C7A_API_DIA_HEADER

#include <functional>
#include <vector>
#include <stack>
#include <iostream>
#include <fstream>
#include <cassert>
#include <memory>
#include <unordered_map>
#include <string>
#include <utility>

#include "dia_node.hpp"
#include "function_traits.hpp"
#include "lop_node.hpp"
#include "zip_node.hpp"
#include "read_node.hpp"
#include "reduce_node.hpp"
#include "context.hpp"
#include "write_node.hpp"

namespace c7a {

//! \addtogroup api Interface
//! \{

/*!
 * DIARef is the interface between the user and the c7a framework. A DIARef can
 * be imagined as an immutable array, even though the data does not need to be
 * materialized at all. A DIARef contains a pointer to a DIANode of type T,
 * which represents the state after the previous DOp or Action. Additionally, a
 * DIARef stores the local lambda function chain of type Stack, which can transform
 * elements of the DIANode to elements of this DIARef. DOps/Actions create a
 * DIARef and a new DIANode, to which the DIARef links to. LOps only create a
 * new DIARef, which link to the previous DIANode.
 *
 * \tparam T Type of elements in this DIARef.
 *
 * \tparam Stack Type of the function chain.
 */
template <typename T, typename Stack = FunctionStack<> >
class DIARef
{
    friend class Context;
    using DIANodePtr = std::shared_ptr<DIANode<T> >;

public:
    /*!
     * Constructor of a new DIARef with a pointer to a DIANode and a
     * function chain from the DIANode to this DIARef.
     *
     * \param node Pointer to the last DIANode, DOps and Actions create a new
     * DIANode, LOps link to the DIANode of the previous DIARef.
     *
     * \param stack Function stack consisting of functions between last DIANode
     * and this DIARef.
     */
    DIARef(DIANodePtr& node, Stack& stack)
        : node_(node),
          local_stack_(stack)
    { }

    /*!
     * Constructor of a new DIARef supporting move semantics of nodes.
     *
     * \param node Pointer to the last DIANode, DOps and Actions create a new
     * DIANode, LOps link to the DIANode of the previous DIARef.
     *
     * \param stack Function stack consisting of functions between last DIANode
     * and this DIARef.
     */
    DIARef(DIANodePtr&& node, Stack& stack)
        : node_(std::move(node)),
          local_stack_(stack)
    { }

    /*!
     * Copy-Constructor of a DIARef with empty function chain
     * from a DIARef with a non-empty chain.
     * The functionality of the chain is stored in a newly created LOpNode.
     * The current DIARef than points to this LOpNode.
     * This is needed to support assignment operations between DIARef's.
     *
     * \param rhs DIA containing a non-empty function chain.
     */
    template <typename AnyStack>
    DIARef(const DIARef<T, AnyStack>& rhs) {
        // Create new LOpNode
        // Transfer stack from rhs to LOpNode
        // Build new DIARef with empty stack and LOpNode
        auto rhs_node = std::move(rhs.get_node());
        auto rhs_stack = rhs.get_stack();
        using LOpChainNode
                  = LOpNode<T, decltype(rhs_stack)>;

        auto shared_node
            = std::make_shared<LOpChainNode>(rhs_node->get_context(),
                                             rhs_node,
                                             rhs_stack);
        node_ = std::move(shared_node);
        local_stack_ = FunctionStack<>();
    }

    /*!
     * Returns a pointer to the according DIANode.
     */
    DIANode<T> * get_node() const {
        return node_.get();
    }

    /*!
     * Returns the number of references to the according DIANode.
     */
    int get_node_count() const {
        return node_.use_count();
    }

    /*!
     * Returns the stored function chain.
     */
    Stack & get_stack() {
        return local_stack_;
    }

    /*!
     * Map is a LOp, which maps this DIARef according to the map_fn given by the
     * user.  The map_fn maps each element to another
     * element of a possibly different type. The DIARef returned by Map has the
     * same type T. The function chain of the returned DIARef is this DIARef's
     * local_stack_ chained with map_fn.
     *
     * \tparam map_fn_t Type of the map function.
     *
     * \param map_fn Map function of type map_fn_t, which maps each element to
     * an element of a possibly different type.
     *
     */
    template <typename map_fn_t>
    auto Map(const map_fn_t &map_fn) {
        using map_arg_t
                  = typename FunctionTraits<map_fn_t>::template arg<0>;
        using map_result_t
                  = typename FunctionTraits<map_fn_t>::result_type;
        auto conv_map_fn = [=](map_arg_t input, std::function<void(map_result_t)> emit_func) {
                               emit_func(map_fn(input));
                           };

        auto new_stack = local_stack_.push(conv_map_fn);
        return DIARef<T, decltype(new_stack)>(node_, new_stack);
    }

    /*!
     * Filter is a LOp, which filters elements from  this DIARef
     * according to the filter_fn given by the
     * user. The filter_fn maps each element to a boolean.
     * The DIARef returned by Filter has the same type T.
     * The function chain of the returned DIARef is this DIARef's
     * local_stack_ chained with filter_fn.
     *
     * \tparam filter_fn_t Type of the map function.
     *
     * \param filter_fn Filter function of type filter_fn_t, which maps each element to
     * a boolean.
     *
     */
    template <typename filter_fn_t>
    auto Filter(const filter_fn_t &filter_fn) {
        using filter_arg_t
                  = typename FunctionTraits<filter_fn_t>::template arg<0>;
        auto conv_filter_fn = [=](filter_arg_t input, std::function<void(filter_arg_t)> emit_func) {
                                  if (filter_fn(input)) emit_func(input);
                              };

        auto new_stack = local_stack_.push(conv_filter_fn);
        return DIARef<T, decltype(new_stack)>(node_, new_stack);
    }

    /*!
     * FlatMap is a LOp, which maps this DIARef according to the flatmap_fn
     * given by the user.  The flatmap_fn maps each element
     * to elements of a possibly different type. The flatmap_fn has an emitter
     * function as it's second parameter. This emitter is called once for each
     * element to be emitted. The DIARef returned by FlatMap has the same type
     * T. The function chain of the returned DIARef is this DIARef's
     * local_stack_ chained with flatmap_fn.
     *
     * \tparam flatmap_fn_t Type of the map function.
     *
     * \param flatmap_fn Map function of type map_fn_t, which maps each element
     * to elements of a possibly different type.
     */
    template <typename flatmap_fn_t>
    auto FlatMap(const flatmap_fn_t &flatmap_fn) {
        auto new_stack = local_stack_.push(flatmap_fn);
        return DIARef<T, decltype(new_stack)>(node_, new_stack);
    }

    /*!
     * Reduce is a DOp, which groups elements of the DIARef with the
     * key_extractor and reduces each key-bucket to a single element using the
     * associative reduce_function. The reduce_function defines how two elements
     * can be reduced to a single element of equal type. Since Reduce is a DOp, it
     * creates a new DIANode. The DIARef returned by Reduce links to this newly
     * created DIANode. The local_stack_ of the returned DIARef consists of
     * the PostOp of Reduce, as a reduced element can
     * directly be chained to the following LOps.
     *
     * \tparam key_extr_fn_t Type of the key_extractor function.
     * The key_extractor function is equal to a map function.
     *
     * \param key_extractor Key extractor function, which maps each element to a
     * key of possibly different type.
     *
     */
    template <typename key_extr_fn_t>
    auto ReduceBy(const key_extr_fn_t &key_extractor) {
        return ReduceSugar<key_extr_fn_t>(key_extractor, node_.get(), local_stack_);
    }

    /*!
     * Zip is a DOp, which Zips two DIAs in style of functional programming. The
     * zip_function is used to zip the i-th elements of both input DIAs together
     * to form the i-th element of the output DIARef. The type of the output
     * DIARef can be inferred from the zip_function.
     *
     * \tparam zip_fn_t Type of the zip_function. This is a function with two
     * input elements, both of the local type, and one output element, which is
     * the type of the Zip node.
     *
     * \param zip_fn Zip function, which zips two elements together
     *
     * \param second_dia DIARef, which is zipped together with the original
     * DIARef.
     */
    template <typename zip_fn_t, typename second_dia_t>
    auto Zip(const zip_fn_t &zip_fn, second_dia_t second_dia) {
        using zip_result_t
                  = typename FunctionTraits<zip_fn_t>::result_type;
        using zip_arg_0_t
                  = typename FunctionTraits<zip_fn_t>::template arg<0>;
        using zip_arg_1_t
                  = typename FunctionTraits<zip_fn_t>::template arg<1>;
        using ZipResultNode
                  = TwoZipNode<zip_arg_0_t, zip_arg_1_t, zip_result_t,
                               decltype(local_stack_), decltype(second_dia.get_stack()), zip_fn_t>;

        auto shared_node
            = std::make_shared<ZipResultNode>(node_->get_context(),
                                              node_.get(),
                                              second_dia.get_node(),
                                              local_stack_,
                                              second_dia.get_stack(),
                                              zip_fn);

        auto zip_stack = shared_node->ProduceStack();
        return DIARef<zip_result_t, decltype(zip_stack)>
                   (std::move(shared_node), zip_stack);
    }

    template <typename write_fn_t>
    void WriteToFileSystem(std::string filepath,
                           const write_fn_t &write_fn) {
        using write_result_t = typename FunctionTraits<write_fn_t>::result_type;

        using WriteResultNode = WriteNode<T, write_result_t, write_fn_t>;

        auto shared_node =
                std::make_shared<WriteResultNode>(node_->get_context(),
                                                  node_.get(),
                                                  write_fn,
                                                  filepath);

        shared_node->ProduceStack();
    }

    /*!
     * Returns Chuck Norris!
     *
     * \return Chuck Norris
     */
    const std::vector<T> & evil_get_data() const {
        return (std::vector<T>{ T() });
    }

    /*!
     * Returns the string which defines the DIANode node_.
     *
     * \return The string of node_
     */
    std::string NodeString() {
        return node_->ToString();
    }

    /*!
     * Prints the DIANode and all it's children recursively. The printing is
     * performed tree-style.
     */
    void PrintNodes() {
        using BasePair = std::pair<DIABase*, int>;
        std::stack<BasePair> dia_stack;
        dia_stack.push(std::make_pair(node_, 0));
        while (!dia_stack.empty()) {
            auto curr = dia_stack.top();
            auto node = curr.first;
            int depth = curr.second;
            dia_stack.pop();
            auto is_end = true;
            if (!dia_stack.empty()) is_end = dia_stack.top().second < depth;
            for (int i = 0; i < depth - 1; ++i) {
                std::cout << "│   ";
            }
            if (is_end && depth > 0) std::cout << "└── ";
            else if (depth > 0) std::cout << "├── ";
            std::cout << node->ToString() << std::endl;
            auto children = node->get_childs();
            for (auto c : children) {
                dia_stack.push(std::make_pair(c, depth + 1));
            }
        }
    }

private:
    //! The DIANode which DIARef points to. The node represents the latest DOp
    //! or Action performed previously.
    DIANodePtr node_;

    //! The local function chain, which stores the chained lambda function from
    //! the last DIANode to this DIARef.
    Stack local_stack_;

    /*!
     * Syntactic sugaaah for reduce
     */
    template <typename key_extr_fn_t>
    class ReduceSugar
    {
    public:
        ReduceSugar(const key_extr_fn_t& key_extractor, DIANode<T>* node, Stack& local_stack)
            : key_extractor_(key_extractor), node_(node), local_stack_(local_stack) { }

        /*!
         * Syntactic sugaaah
         *
         * \tparam reduce_fn_t Type of the reduce_function. This is a function
         * reducing two elements of L's result type to a single element of equal
         * type.
         *
         * \param reduce_function Reduce function, which defines how the key
         * buckets are reduced to a single element. This function is applied
         * associative but not necessarily commutative.
         *
         */
        template <typename reduce_fn_t>
        auto With(const reduce_fn_t &reduce_function) {
            using dop_result_t
                      = typename FunctionTraits<reduce_fn_t>::result_type;
            using ReduceResultNode
                      = ReduceNode<T, dop_result_t, decltype(local_stack_), key_extr_fn_t, reduce_fn_t>;

            auto shared_node
                = std::make_shared<ReduceResultNode>(node_->get_context(),
                                                     node_,
                                                     local_stack_,
                                                     key_extractor_,
                                                     reduce_function);

            auto reduce_stack = shared_node->ProduceStack();

            return DIARef<dop_result_t, decltype(reduce_stack)>
                       (std::move(shared_node), reduce_stack);
        }

    private:
        const key_extr_fn_t& key_extractor_;
        DIANode<T>* node_;
        Stack& local_stack_;
    };
};

//! \}

template <typename read_fn_t>
auto ReadFromFileSystem(Context & ctx, std::string filepath,
                        const read_fn_t &read_fn) {
    using read_result_t = typename FunctionTraits<read_fn_t>::result_type;
    using ReadResultNode = ReadNode<read_result_t, read_fn_t>;

    auto shared_node =
        std::make_shared<ReadResultNode>(ctx,
                                         read_fn,
                                         filepath);

    auto read_stack = shared_node->ProduceStack();

    return DIARef<read_result_t, decltype(read_stack)>
               (std::move(shared_node), read_stack);
}

} // namespace c7a

#endif // !C7A_API_DIA_HEADER

/******************************************************************************/
<commit_msg>added doc to WriteToFileSystem<commit_after>/*******************************************************************************
 * c7a/api/dia.hpp
 *
 * Interface for Operations, holds pointer to node and lambda from node to state
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_API_DIA_HEADER
#define C7A_API_DIA_HEADER

#include <functional>
#include <vector>
#include <stack>
#include <iostream>
#include <fstream>
#include <cassert>
#include <memory>
#include <unordered_map>
#include <string>
#include <utility>

#include "dia_node.hpp"
#include "function_traits.hpp"
#include "lop_node.hpp"
#include "zip_node.hpp"
#include "read_node.hpp"
#include "reduce_node.hpp"
#include "context.hpp"
#include "write_node.hpp"

namespace c7a {

//! \addtogroup api Interface
//! \{

/*!
 * DIARef is the interface between the user and the c7a framework. A DIARef can
 * be imagined as an immutable array, even though the data does not need to be
 * materialized at all. A DIARef contains a pointer to a DIANode of type T,
 * which represents the state after the previous DOp or Action. Additionally, a
 * DIARef stores the local lambda function chain of type Stack, which can transform
 * elements of the DIANode to elements of this DIARef. DOps/Actions create a
 * DIARef and a new DIANode, to which the DIARef links to. LOps only create a
 * new DIARef, which link to the previous DIANode.
 *
 * \tparam T Type of elements in this DIARef.
 *
 * \tparam Stack Type of the function chain.
 */
template <typename T, typename Stack = FunctionStack<> >
class DIARef
{
    friend class Context;
    using DIANodePtr = std::shared_ptr<DIANode<T> >;

public:
    /*!
     * Constructor of a new DIARef with a pointer to a DIANode and a
     * function chain from the DIANode to this DIARef.
     *
     * \param node Pointer to the last DIANode, DOps and Actions create a new
     * DIANode, LOps link to the DIANode of the previous DIARef.
     *
     * \param stack Function stack consisting of functions between last DIANode
     * and this DIARef.
     */
    DIARef(DIANodePtr& node, Stack& stack)
        : node_(node),
          local_stack_(stack)
    { }

    /*!
     * Constructor of a new DIARef supporting move semantics of nodes.
     *
     * \param node Pointer to the last DIANode, DOps and Actions create a new
     * DIANode, LOps link to the DIANode of the previous DIARef.
     *
     * \param stack Function stack consisting of functions between last DIANode
     * and this DIARef.
     */
    DIARef(DIANodePtr&& node, Stack& stack)
        : node_(std::move(node)),
          local_stack_(stack)
    { }

    /*!
     * Copy-Constructor of a DIARef with empty function chain
     * from a DIARef with a non-empty chain.
     * The functionality of the chain is stored in a newly created LOpNode.
     * The current DIARef than points to this LOpNode.
     * This is needed to support assignment operations between DIARef's.
     *
     * \param rhs DIA containing a non-empty function chain.
     */
    template <typename AnyStack>
    DIARef(const DIARef<T, AnyStack>& rhs) {
        // Create new LOpNode
        // Transfer stack from rhs to LOpNode
        // Build new DIARef with empty stack and LOpNode
        auto rhs_node = std::move(rhs.get_node());
        auto rhs_stack = rhs.get_stack();
        using LOpChainNode
                  = LOpNode<T, decltype(rhs_stack)>;

        auto shared_node
            = std::make_shared<LOpChainNode>(rhs_node->get_context(),
                                             rhs_node,
                                             rhs_stack);
        node_ = std::move(shared_node);
        local_stack_ = FunctionStack<>();
    }

    /*!
     * Returns a pointer to the according DIANode.
     */
    DIANode<T> * get_node() const {
        return node_.get();
    }

    /*!
     * Returns the number of references to the according DIANode.
     */
    int get_node_count() const {
        return node_.use_count();
    }

    /*!
     * Returns the stored function chain.
     */
    Stack & get_stack() {
        return local_stack_;
    }

    /*!
     * Map is a LOp, which maps this DIARef according to the map_fn given by the
     * user.  The map_fn maps each element to another
     * element of a possibly different type. The DIARef returned by Map has the
     * same type T. The function chain of the returned DIARef is this DIARef's
     * local_stack_ chained with map_fn.
     *
     * \tparam map_fn_t Type of the map function.
     *
     * \param map_fn Map function of type map_fn_t, which maps each element to
     * an element of a possibly different type.
     *
     */
    template <typename map_fn_t>
    auto Map(const map_fn_t &map_fn) {
        using map_arg_t
                  = typename FunctionTraits<map_fn_t>::template arg<0>;
        using map_result_t
                  = typename FunctionTraits<map_fn_t>::result_type;
        auto conv_map_fn = [=](map_arg_t input, std::function<void(map_result_t)> emit_func) {
                               emit_func(map_fn(input));
                           };

        auto new_stack = local_stack_.push(conv_map_fn);
        return DIARef<T, decltype(new_stack)>(node_, new_stack);
    }

    /*!
     * Filter is a LOp, which filters elements from  this DIARef
     * according to the filter_fn given by the
     * user. The filter_fn maps each element to a boolean.
     * The DIARef returned by Filter has the same type T.
     * The function chain of the returned DIARef is this DIARef's
     * local_stack_ chained with filter_fn.
     *
     * \tparam filter_fn_t Type of the map function.
     *
     * \param filter_fn Filter function of type filter_fn_t, which maps each element to
     * a boolean.
     *
     */
    template <typename filter_fn_t>
    auto Filter(const filter_fn_t &filter_fn) {
        using filter_arg_t
                  = typename FunctionTraits<filter_fn_t>::template arg<0>;
        auto conv_filter_fn = [=](filter_arg_t input, std::function<void(filter_arg_t)> emit_func) {
                                  if (filter_fn(input)) emit_func(input);
                              };

        auto new_stack = local_stack_.push(conv_filter_fn);
        return DIARef<T, decltype(new_stack)>(node_, new_stack);
    }

    /*!
     * FlatMap is a LOp, which maps this DIARef according to the flatmap_fn
     * given by the user.  The flatmap_fn maps each element
     * to elements of a possibly different type. The flatmap_fn has an emitter
     * function as it's second parameter. This emitter is called once for each
     * element to be emitted. The DIARef returned by FlatMap has the same type
     * T. The function chain of the returned DIARef is this DIARef's
     * local_stack_ chained with flatmap_fn.
     *
     * \tparam flatmap_fn_t Type of the map function.
     *
     * \param flatmap_fn Map function of type map_fn_t, which maps each element
     * to elements of a possibly different type.
     */
    template <typename flatmap_fn_t>
    auto FlatMap(const flatmap_fn_t &flatmap_fn) {
        auto new_stack = local_stack_.push(flatmap_fn);
        return DIARef<T, decltype(new_stack)>(node_, new_stack);
    }

    /*!
     * Reduce is a DOp, which groups elements of the DIARef with the
     * key_extractor and reduces each key-bucket to a single element using the
     * associative reduce_function. The reduce_function defines how two elements
     * can be reduced to a single element of equal type. Since Reduce is a DOp, it
     * creates a new DIANode. The DIARef returned by Reduce links to this newly
     * created DIANode. The local_stack_ of the returned DIARef consists of
     * the PostOp of Reduce, as a reduced element can
     * directly be chained to the following LOps.
     *
     * \tparam key_extr_fn_t Type of the key_extractor function.
     * The key_extractor function is equal to a map function.
     *
     * \param key_extractor Key extractor function, which maps each element to a
     * key of possibly different type.
     *
     */
    template <typename key_extr_fn_t>
    auto ReduceBy(const key_extr_fn_t &key_extractor) {
        return ReduceSugar<key_extr_fn_t>(key_extractor, node_.get(), local_stack_);
    }

    /*!
     * Zip is a DOp, which Zips two DIAs in style of functional programming. The
     * zip_function is used to zip the i-th elements of both input DIAs together
     * to form the i-th element of the output DIARef. The type of the output
     * DIARef can be inferred from the zip_function.
     *
     * \tparam zip_fn_t Type of the zip_function. This is a function with two
     * input elements, both of the local type, and one output element, which is
     * the type of the Zip node.
     *
     * \param zip_fn Zip function, which zips two elements together
     *
     * \param second_dia DIARef, which is zipped together with the original
     * DIARef.
     */
    template <typename zip_fn_t, typename second_dia_t>
    auto Zip(const zip_fn_t &zip_fn, second_dia_t second_dia) {
        using zip_result_t
                  = typename FunctionTraits<zip_fn_t>::result_type;
        using zip_arg_0_t
                  = typename FunctionTraits<zip_fn_t>::template arg<0>;
        using zip_arg_1_t
                  = typename FunctionTraits<zip_fn_t>::template arg<1>;
        using ZipResultNode
                  = TwoZipNode<zip_arg_0_t, zip_arg_1_t, zip_result_t,
                               decltype(local_stack_), decltype(second_dia.get_stack()), zip_fn_t>;

        auto shared_node
            = std::make_shared<ZipResultNode>(node_->get_context(),
                                              node_.get(),
                                              second_dia.get_node(),
                                              local_stack_,
                                              second_dia.get_stack(),
                                              zip_fn);

        auto zip_stack = shared_node->ProduceStack();
        return DIARef<zip_result_t, decltype(zip_stack)>
                   (std::move(shared_node), zip_stack);
    }

    /*!
     * WriteToFileSystem is an Action, which writes elements to an output file. A
     * provided function is used prepare the elements before written.
     *
     * \tparam write_fn_t Type of the write_function. This is a function with one
     * input element of the local type.
     *
     * \param write_fn Write function, which prepares an element to be written to disk.
     *
     * \param filepath Destination of the output file.
     */
    template <typename write_fn_t>
    void WriteToFileSystem(std::string filepath,
                           const write_fn_t &write_fn) {
        using write_result_t = typename FunctionTraits<write_fn_t>::result_type;

        using WriteResultNode = WriteNode<T, write_result_t, write_fn_t>;

        auto shared_node =
                std::make_shared<WriteResultNode>(node_->get_context(),
                                                  node_.get(),
                                                  write_fn,
                                                  filepath);

        shared_node->ProduceStack();
    }

    /*!
     * Returns Chuck Norris!
     *
     * \return Chuck Norris
     */
    const std::vector<T> & evil_get_data() const {
        return (std::vector<T>{ T() });
    }

    /*!
     * Returns the string which defines the DIANode node_.
     *
     * \return The string of node_
     */
    std::string NodeString() {
        return node_->ToString();
    }

    /*!
     * Prints the DIANode and all it's children recursively. The printing is
     * performed tree-style.
     */
    void PrintNodes() {
        using BasePair = std::pair<DIABase*, int>;
        std::stack<BasePair> dia_stack;
        dia_stack.push(std::make_pair(node_, 0));
        while (!dia_stack.empty()) {
            auto curr = dia_stack.top();
            auto node = curr.first;
            int depth = curr.second;
            dia_stack.pop();
            auto is_end = true;
            if (!dia_stack.empty()) is_end = dia_stack.top().second < depth;
            for (int i = 0; i < depth - 1; ++i) {
                std::cout << "│   ";
            }
            if (is_end && depth > 0) std::cout << "└── ";
            else if (depth > 0) std::cout << "├── ";
            std::cout << node->ToString() << std::endl;
            auto children = node->get_childs();
            for (auto c : children) {
                dia_stack.push(std::make_pair(c, depth + 1));
            }
        }
    }

private:
    //! The DIANode which DIARef points to. The node represents the latest DOp
    //! or Action performed previously.
    DIANodePtr node_;

    //! The local function chain, which stores the chained lambda function from
    //! the last DIANode to this DIARef.
    Stack local_stack_;

    /*!
     * Syntactic sugaaah for reduce
     */
    template <typename key_extr_fn_t>
    class ReduceSugar
    {
    public:
        ReduceSugar(const key_extr_fn_t& key_extractor, DIANode<T>* node, Stack& local_stack)
            : key_extractor_(key_extractor), node_(node), local_stack_(local_stack) { }

        /*!
         * Syntactic sugaaah
         *
         * \tparam reduce_fn_t Type of the reduce_function. This is a function
         * reducing two elements of L's result type to a single element of equal
         * type.
         *
         * \param reduce_function Reduce function, which defines how the key
         * buckets are reduced to a single element. This function is applied
         * associative but not necessarily commutative.
         *
         */
        template <typename reduce_fn_t>
        auto With(const reduce_fn_t &reduce_function) {
            using dop_result_t
                      = typename FunctionTraits<reduce_fn_t>::result_type;
            using ReduceResultNode
                      = ReduceNode<T, dop_result_t, decltype(local_stack_), key_extr_fn_t, reduce_fn_t>;

            auto shared_node
                = std::make_shared<ReduceResultNode>(node_->get_context(),
                                                     node_,
                                                     local_stack_,
                                                     key_extractor_,
                                                     reduce_function);

            auto reduce_stack = shared_node->ProduceStack();

            return DIARef<dop_result_t, decltype(reduce_stack)>
                       (std::move(shared_node), reduce_stack);
        }

    private:
        const key_extr_fn_t& key_extractor_;
        DIANode<T>* node_;
        Stack& local_stack_;
    };
};

//! \}

template <typename read_fn_t>
auto ReadFromFileSystem(Context & ctx, std::string filepath,
                        const read_fn_t &read_fn) {
    using read_result_t = typename FunctionTraits<read_fn_t>::result_type;
    using ReadResultNode = ReadNode<read_result_t, read_fn_t>;

    auto shared_node =
        std::make_shared<ReadResultNode>(ctx,
                                         read_fn,
                                         filepath);

    auto read_stack = shared_node->ProduceStack();

    return DIARef<read_result_t, decltype(read_stack)>
               (std::move(shared_node), read_stack);
}

} // namespace c7a

#endif // !C7A_API_DIA_HEADER

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


<commit_before>/****************************************************************************
** Meta object code from reading C++ file 'LogDock.h'
**
** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.5)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

#include "src/Widgets/LogDock.h"
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'LogDock.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 63
#error "This file was generated using the moc from 4.8.5. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif

QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_LogDock[] = {

 // content:
       6,       // revision
       0,       // classname
       0,    0, // classinfo
       0,    0, // methods
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       0,       // signalCount

       0        // eod
};

static const char qt_meta_stringdata_LogDock[] = {
    "LogDock\0"
};

void LogDock::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    Q_UNUSED(_o);
    Q_UNUSED(_id);
    Q_UNUSED(_c);
    Q_UNUSED(_a);
}

const QMetaObjectExtraData LogDock::staticMetaObjectExtraData = {
    0,  qt_static_metacall
};

const QMetaObject LogDock::staticMetaObject = {
    { &QDockWidget::staticMetaObject, qt_meta_stringdata_LogDock,
      qt_meta_data_LogDock, &staticMetaObjectExtraData }
};

#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &LogDock::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION

const QMetaObject *LogDock::metaObject() const
{
    return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}

void *LogDock::qt_metacast(const char *_clname)
{
    if (!_clname) return 0;
    if (!strcmp(_clname, qt_meta_stringdata_LogDock))
        return static_cast<void*>(const_cast< LogDock*>(this));
    return QDockWidget::qt_metacast(_clname);
}

int LogDock::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    _id = QDockWidget::qt_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    return _id;
}
QT_END_MOC_NAMESPACE
<commit_msg>Delete moc_LogDock.cpp<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2015-2017 Two Pore Guys, Inc.
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "catch.hpp"

#include <rpc/object.h>
#include "../src/internal.h"

#include <glib/gprintf.h>

SCENARIO("RPC_NULL_OBJECT", "Create a NULL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t copy;
		object = rpc_null_create();

		THEN("Type is NULL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_NULL);
		}

		AND_THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}
	}
}

SCENARIO("RPC_BOOL_OBJECT", "Create a BOOL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		bool value = true;
		bool different_value = false;
		object = rpc_bool_create(value);
		different_object = rpc_bool_create(different_value);

		THEN("Type is BOOL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_BOOL);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_bool_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_b == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_UINT64_OBJECT", "Create a UINT64 RPC object and perform basic operations on it") {
	GIVEN("UINT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		uint64_t value = 1234;
		uint64_t different_value = 5678;
		object = rpc_uint64_create(value);
		different_object = rpc_uint64_create(different_value);

		THEN("Type is UINT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_UINT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_uint64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_ui == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_INT64_OBJECT", "Create a INT64 RPC object and perform basic operations on it") {
	GIVEN("INT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		int64_t value = 1234;
		int64_t different_value = -1234;
		object = rpc_int64_create(value);
		different_object = rpc_int64_create(different_value);

		THEN("Type is INT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_INT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_int64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_i == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DOUBLE_OBJECT", "Create a DOUBLE RPC object and perform basic operations on it") {
	GIVEN("DOUBLE object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		double value = 12.34;
		double different_value = -12.34;
		object = rpc_double_create(value);
		different_object = rpc_double_create(different_value);

		THEN("Type is DOUBLE") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_DOUBLE);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_double_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_d == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DESCRIPTION_TEST", "Create a tree of RPC objects and print their description") {
	GIVEN("RPC objects tree") {
		int data = 0xff00ff00;
		static const char *referene = "<dictionary> {\n"
		    "    null_val: <null> ,\n"
		    "    array: <array> [\n"
		    "        0: <null> ,\n"
		    "        1: <bool> true,\n"
		    "        2: <uint64> 1234,\n"
		    "        3: <int64> -1234,\n"
		    "        4: <double> 12.340000,\n"
		    "        5: <date> 1970-01-01 00:00:00,\n"
		    "        6: <string> \"test string\",\n"
		    "        7: <binary> 00ff00ff,\n"
		    "        8: <fd> 10,\n"
		    "    ],\n"
		    "    test_string2: <string> \"test_test_test\",\n"
		    "}\n";

		rpc_object_t null = rpc_null_create();
		rpc_object_t boolean = rpc_bool_create(true);
		rpc_object_t u_integer = rpc_uint64_create(1234);
		rpc_object_t integer = rpc_int64_create(-1234);
		rpc_object_t dbl = rpc_double_create(12.34);
		rpc_object_t date = rpc_date_create(0);
		rpc_object_t string = rpc_string_create("test string");
		rpc_object_t binary = rpc_data_create(&data, sizeof(data), false);
		rpc_object_t fd = rpc_fd_create(10);
		rpc_object_t dict = rpc_dictionary_create();
		rpc_object_t array = rpc_array_create();

		rpc_array_append_stolen_value(array, null);
		rpc_array_append_stolen_value(array, boolean);
		rpc_array_append_stolen_value(array, u_integer);
		rpc_array_append_stolen_value(array, integer);
		rpc_array_append_stolen_value(array, dbl);
		rpc_array_append_stolen_value(array, date);
		rpc_array_append_stolen_value(array, string);
		rpc_array_append_stolen_value(array, binary);
		rpc_array_append_stolen_value(array, fd);

		rpc_dictionary_set_value(dict, "null_val", null);
		rpc_dictionary_set_value(dict, "array", array);

		rpc_dictionary_set_string(dict, "test_string2", "test_test_test");

		THEN("Parent RPC object's description is equal to refrence description") {
			REQUIRE(g_strcmp0(referene, rpc_copy_description(dict)) == 0);
		}
	}
}
<commit_msg>FIXED: make sure to free memory in tests<commit_after>/*
 * Copyright 2015-2017 Two Pore Guys, Inc.
 * All rights reserved
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted providing 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 "catch.hpp"

#include <rpc/object.h>
#include "../src/internal.h"

SCENARIO("RPC_NULL_OBJECT", "Create a NULL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t copy;
		object = rpc_null_create();

		THEN("Type is NULL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_NULL);
		}

		AND_THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}
	}
}

SCENARIO("RPC_BOOL_OBJECT", "Create a BOOL RPC object and perform basic operations on it") {
	GIVEN("BOOL object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		bool value = true;
		bool different_value = false;
		object = rpc_bool_create(value);
		different_object = rpc_bool_create(different_value);

		THEN("Type is BOOL") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_BOOL);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_bool_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_b == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_UINT64_OBJECT", "Create a UINT64 RPC object and perform basic operations on it") {
	GIVEN("UINT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		uint64_t value = 1234;
		uint64_t different_value = 5678;
		object = rpc_uint64_create(value);
		different_object = rpc_uint64_create(different_value);

		THEN("Type is UINT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_UINT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_uint64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_ui == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_INT64_OBJECT", "Create a INT64 RPC object and perform basic operations on it") {
	GIVEN("INT64 object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		int64_t value = 1234;
		int64_t different_value = -1234;
		object = rpc_int64_create(value);
		different_object = rpc_int64_create(different_value);

		THEN("Type is INT64") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_INT64);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_int64_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_i == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DOUBLE_OBJECT", "Create a DOUBLE RPC object and perform basic operations on it") {
	GIVEN("DOUBLE object") {
		rpc_object_t object;
		rpc_object_t different_object;
		rpc_object_t copy;
		double value = 12.34;
		double different_value = -12.34;
		object = rpc_double_create(value);
		different_object = rpc_double_create(different_value);

		THEN("Type is DOUBLE") {
			REQUIRE(rpc_get_type(object) == RPC_TYPE_DOUBLE);
		}

		THEN("Refcount equals 1") {
			REQUIRE(object->ro_refcnt == 1);
		}

		THEN("Extracted value matches") {
			REQUIRE(rpc_double_get_value(object) == value);
		}

		AND_THEN("Direct value matches") {
			REQUIRE(object->ro_value.rv_d == value);
		}

		WHEN("Object's copy is created") {
			copy = rpc_copy(object);

			THEN("Source and copy are equal"){
				REQUIRE(rpc_equal(object, copy));
			}

			AND_THEN("Object is different from object initialized with different value") {
				REQUIRE(!rpc_equal(object, different_object));
			}
		}

		WHEN("reference count is incremented") {
			rpc_retain(object);

			THEN("reference count equals 2"){
				REQUIRE(object->ro_refcnt == 2);
			}

			AND_WHEN("reference count is decremented") {
				rpc_release(object);

				THEN("reference count equals 1") {
					REQUIRE(object->ro_refcnt == 1);
				}

				AND_WHEN("reference count reaches 0") {
					rpc_release(object);

					THEN("RPC object pointer is NULL") {
						REQUIRE(object == NULL);
					}
				}
			}
		}

		rpc_release(different_object);
	}
}

SCENARIO("RPC_DESCRIPTION_TEST", "Create a tree of RPC objects and print their description") {
	GIVEN("RPC objects tree") {
		int data = 0xff00ff00;
		static const char *referene = "<dictionary> {\n"
		    "    null_val: <null> ,\n"
		    "    array: <array> [\n"
		    "        0: <null> ,\n"
		    "        1: <bool> true,\n"
		    "        2: <uint64> 1234,\n"
		    "        3: <int64> -1234,\n"
		    "        4: <double> 12.340000,\n"
		    "        5: <date> 1970-01-01 00:00:00,\n"
		    "        6: <string> \"test string\",\n"
		    "        7: <binary> 00ff00ff,\n"
		    "        8: <fd> 10,\n"
		    "    ],\n"
		    "    test_string2: <string> \"test_test_test\",\n"
		    "}\n";

		rpc_object_t null = rpc_null_create();
		rpc_object_t boolean = rpc_bool_create(true);
		rpc_object_t u_integer = rpc_uint64_create(1234);
		rpc_object_t integer = rpc_int64_create(-1234);
		rpc_object_t dbl = rpc_double_create(12.34);
		rpc_object_t date = rpc_date_create(0);
		rpc_object_t string = rpc_string_create("test string");
		rpc_object_t binary = rpc_data_create(&data, sizeof(data), false);
		rpc_object_t fd = rpc_fd_create(10);
		rpc_object_t dict = rpc_dictionary_create();
		rpc_object_t array = rpc_array_create();

		rpc_array_append_stolen_value(array, null);
		rpc_array_append_stolen_value(array, boolean);
		rpc_array_append_stolen_value(array, u_integer);
		rpc_array_append_stolen_value(array, integer);
		rpc_array_append_stolen_value(array, dbl);
		rpc_array_append_stolen_value(array, date);
		rpc_array_append_stolen_value(array, string);
		rpc_array_append_stolen_value(array, binary);
		rpc_array_append_stolen_value(array, fd);

		rpc_dictionary_set_value(dict, "null_val", null);
		rpc_dictionary_set_value(dict, "array", array);

		rpc_dictionary_set_string(dict, "test_string2", "test_test_test");

		THEN("Parent RPC object's description is equal to refrence description") {
			REQUIRE(g_strcmp0(referene, rpc_copy_description(dict)) == 0);
		}

		rpc_release(dict);
	}
}
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011,2012 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library 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 2.1 of the License, or (at your option) any later version.
//
// This library 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 this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "global_id_generator.hpp"
#include "exception.hpp"
#include <cassert>

#ifndef ATOMIC_I8_SUPPORT
#include <pficommon/concurrent/lock.h>
#include <pficommon/concurrent/mutex.h>
#endif

namespace jubatus { namespace common {

class global_id_generator_impl {
 private:
  bool is_standalone_;
  uint64_t counter_;
  std::string path_;
  cshared_ptr<lock_service> ls_;

#ifndef ATOMIC_I8_SUPPORT
  pfi::concurrent::mutex counter_mutex_;
#endif

 public:
  global_id_generator_impl():
    is_standalone_(true),
    counter_(0)
  {}

  global_id_generator_impl(bool is_standalone):
    is_standalone_(is_standalone),
    counter_(0)
  {}

  uint64_t generate()
  {
    if(is_standalone_){

#ifdef ATOMIC_I8_SUPPORT
      return __sync_fetch_and_add(&counter_, 1);
#else
      pfi::concurrent::scoped_lock lk(counter_mutex_);
      return ++counter_;
#endif

    }else{

#ifdef HAVE_ZOOKEEPER_H
      uint64_t res;
      if (ls_->create_id(path_, 0, res))
        return res;
      else
        throw JUBATUS_EXCEPTION(jubatus::exception::runtime_error("Failed to create id"));
#else
      // never reaches here
      assert(is_standalone_);
      return 0; // dummy to remove warning
#endif

    }
  }

  void set_ls(cshared_ptr<lock_service>& ls,
              const std::string& path_prefix)
  {

#ifdef HAVE_ZOOKEEPER_H
    if (!is_standalone_) {
      path_ = path_prefix + "/id_generator";
      ls_ = ls;
      if (!ls_->create(path_))
        throw JUBATUS_EXCEPTION(jubatus::exception::runtime_error("Failed to create global id generator")
            << jubatus::exception::error_api_func("lock_service::create")
            << jubatus::exception::error_message(path_));
    }
#endif

  }
};

global_id_generator::global_id_generator():
  pimpl_(new global_id_generator_impl())
{}

global_id_generator::global_id_generator(bool is_standalone):
  pimpl_(new global_id_generator_impl(is_standalone))
{}

global_id_generator::~global_id_generator()
{}

uint64_t global_id_generator::generate()
{
  return pimpl_->generate();
}

void global_id_generator::set_ls(cshared_ptr<lock_service>& ls,
                                 const std::string& path_prefix)
{
  pimpl_->set_ls(ls, path_prefix);
}

}}
<commit_msg>fix initial value of global_id_generator (fix #165)<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011,2012 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library 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 2.1 of the License, or (at your option) any later version.
//
// This library 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 this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "global_id_generator.hpp"
#include "exception.hpp"
#include <cassert>

#ifndef ATOMIC_I8_SUPPORT
#include <pficommon/concurrent/lock.h>
#include <pficommon/concurrent/mutex.h>
#endif

namespace jubatus { namespace common {

class global_id_generator_impl {
 private:
  bool is_standalone_;
  uint64_t counter_;
  std::string path_;
  cshared_ptr<lock_service> ls_;

#ifndef ATOMIC_I8_SUPPORT
  pfi::concurrent::mutex counter_mutex_;
#endif

 public:
  global_id_generator_impl():
    is_standalone_(true),
    counter_(0)
  {}

  global_id_generator_impl(bool is_standalone):
    is_standalone_(is_standalone),
    counter_(0)
  {}

  uint64_t generate()
  {
    if(is_standalone_){

#ifdef ATOMIC_I8_SUPPORT
      return __sync_fetch_and_add(&counter_, 1);
#else
      pfi::concurrent::scoped_lock lk(counter_mutex_);
      return counter_++;
#endif

    }else{

#ifdef HAVE_ZOOKEEPER_H
      uint64_t res;
      if (ls_->create_id(path_, 0, res))
        return res;
      else
        throw JUBATUS_EXCEPTION(jubatus::exception::runtime_error("Failed to create id"));
#else
      // never reaches here
      assert(is_standalone_);
      return 0; // dummy to remove warning
#endif

    }
  }

  void set_ls(cshared_ptr<lock_service>& ls,
              const std::string& path_prefix)
  {

#ifdef HAVE_ZOOKEEPER_H
    if (!is_standalone_) {
      path_ = path_prefix + "/id_generator";
      ls_ = ls;
      if (!ls_->create(path_))
        throw JUBATUS_EXCEPTION(jubatus::exception::runtime_error("Failed to create global id generator")
            << jubatus::exception::error_api_func("lock_service::create")
            << jubatus::exception::error_message(path_));
    }
#endif

  }
};

global_id_generator::global_id_generator():
  pimpl_(new global_id_generator_impl())
{}

global_id_generator::global_id_generator(bool is_standalone):
  pimpl_(new global_id_generator_impl(is_standalone))
{}

global_id_generator::~global_id_generator()
{}

uint64_t global_id_generator::generate()
{
  return pimpl_->generate();
}

void global_id_generator::set_ls(cshared_ptr<lock_service>& ls,
                                 const std::string& path_prefix)
{
  pimpl_->set_ls(ls, path_prefix);
}

}}
<|endoftext|>


<commit_before>#include "invertebrate.h"

Invertebrate::Invertebrate()
{

}

bool Invertebrate::operator <(const Invertebrate& inv) const
{
    return name < inv.name;
}

bool Invertebrate::operator >(const Invertebrate& inv) const
{
    return name > inv.name;
}

bool Invertebrate::operator ==(const Invertebrate& inv) const
{
    return name == inv.name;
}

QDataStream &operator<<(QDataStream &ds, const Invertebrate &obj) {
    ds  << obj.commonName
        << obj.description
        << obj.family
        << obj.flyName
        << obj.genus
        << obj.imageFileLocal
        << obj.imageFileRemote
        << obj.imageIsReady
        << obj.imageIsUpToDate
        << obj.name;

    return ds;
}

QDataStream &operator>>(QDataStream &ds, Invertebrate &obj) {
    ds >> obj.commonName;
    ds >> obj.description;
    ds >> obj.family;
    ds >> obj.flyName;
    ds >> obj.genus;
    ds >> obj.imageFileLocal;
    ds >> obj.imageFileRemote;
    ds >> obj.imageIsReady;
    ds >> obj.imageIsUpToDate;
    ds >> obj.name;

    return ds;
}

QDebug operator<<(QDebug debug, const Invertebrate &invertebrate)
{
    QDebugStateSaver saver(debug);
    QStringList list{invertebrate.name, invertebrate.commonName, invertebrate.description, invertebrate.family, invertebrate.flyName, invertebrate.genus, invertebrate.imageFileLocal, invertebrate.imageFileRemote};
    debug.nospace() << "(" << list.join(", ") << ")";

    return debug;
}
<commit_msg>Improved QDebug implmentation for Invertebrate<commit_after>#include "invertebrate.h"

Invertebrate::Invertebrate()
{

}

bool Invertebrate::operator <(const Invertebrate& inv) const
{
    return name < inv.name;
}

bool Invertebrate::operator >(const Invertebrate& inv) const
{
    return name > inv.name;
}

bool Invertebrate::operator ==(const Invertebrate& inv) const
{
    return name == inv.name;
}

QDataStream &operator<<(QDataStream &ds, const Invertebrate &obj) {
    ds  << obj.commonName
        << obj.description
        << obj.family
        << obj.flyName
        << obj.genus
        << obj.imageFileLocal
        << obj.imageFileRemote
        << obj.imageIsReady
        << obj.imageIsUpToDate
        << obj.name;

    return ds;
}

QDataStream &operator>>(QDataStream &ds, Invertebrate &obj) {
    ds >> obj.commonName;
    ds >> obj.description;
    ds >> obj.family;
    ds >> obj.flyName;
    ds >> obj.genus;
    ds >> obj.imageFileLocal;
    ds >> obj.imageFileRemote;
    ds >> obj.imageIsReady;
    ds >> obj.imageIsUpToDate;
    ds >> obj.name;

    return ds;
}

QDebug operator<<(QDebug debug, const Invertebrate &invertebrate)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << "(\n" <<
                       "    commonName: " << invertebrate.commonName << ",\n" <<
                       "    description: " << invertebrate.description << ",\n" <<
                       "    family: " << invertebrate.family << ",\n" <<
                       "    flyName: " << invertebrate.flyName << ",\n" <<
                       "    genus: " << invertebrate.genus << ",\n" <<
                       "    imageFileLocal: " << invertebrate.imageFileLocal << ",\n" <<
                       "    imageFileRemote: " << invertebrate.imageFileRemote << ",\n" <<
                       "    imageIsReady: " << invertebrate.imageIsReady << ",\n" <<
                       "    imageIsUpToDate: " << invertebrate.imageIsUpToDate << ",\n" <<
                       "    name: " << invertebrate.name << ",\n" <<
                       "    order: " << invertebrate.order <<
                       "\n)";

    return debug;
}
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Single cell view widget
//==============================================================================

#include "cellmlfilemanager.h"
#include "singlecellviewsimulationwidget.h"
#include "singlecellviewwidget.h"

//==============================================================================

#include "ui_singlecellviewwidget.h"

//==============================================================================

namespace OpenCOR {
namespace SingleCellView {

//==============================================================================

SingleCellViewWidget::SingleCellViewWidget(SingleCellViewPlugin *pPlugin,
                                           QWidget *pParent) :
    ViewWidget(pParent),
    mPlugin(pPlugin),
    mSimulationWidget(0),
    mSimulationWidgets(QMap<QString, SingleCellViewSimulationWidget *>())
{
}

//==============================================================================

void SingleCellViewWidget::retranslateUi()
{
    // Retranslate our simulation widgets

    foreach (SingleCellViewSimulationWidget *simulationWidget, mSimulationWidgets)
        simulationWidget->retranslateUi();
}

//==============================================================================

bool SingleCellViewWidget::contains(const QString &pFileName) const
{
    // Return whether we know about the given file

    return mSimulationWidgets.contains(pFileName);
}

//==============================================================================

void SingleCellViewWidget::initialize(const QString &pFileName)
{
    // Retrieve the simulation widget associated with the given file, if any

    SingleCellViewSimulationWidget *oldSimulationWidget = mSimulationWidget;

    mSimulationWidget = mSimulationWidgets.value(pFileName);

    if (!mSimulationWidget) {
        // No simulation widget exists for the given file, so create one

        mSimulationWidget = new SingleCellViewSimulationWidget(mPlugin, this);

        // Keep track of our editing widget and add it to ourselves

        mSimulationWidgets.insert(pFileName, mSimulationWidget);

        layout()->addWidget(mSimulationWidget);
    }

    // Hide our previous simulation widget and show our new one

    mSimulationWidget->show();

    if (oldSimulationWidget && (mSimulationWidget != oldSimulationWidget))
        oldSimulationWidget->hide();

    // Set our focus proxy to our 'new' simulation widget and make sure that the
    // latter immediately gets the focus

    setFocusProxy(mSimulationWidget);

    mSimulationWidget->setFocus();
}

//==============================================================================

void SingleCellViewWidget::finalize(const QString &pFileName)
{
    // Remove the simulation widget, should there be one for the given file

    SingleCellViewSimulationWidget *simulationWidget = mSimulationWidgets.value(pFileName);

    if (simulationWidget) {
        // There is a simulation widget for the given file name, so delete it
        // and remove it from our list

        delete simulationWidget;

        mSimulationWidgets.remove(pFileName);

        // Reset our memory of the current editor, if needed

        if (simulationWidget == mSimulationWidget)
            mSimulationWidget = 0;
    }
}

//==============================================================================

void SingleCellViewWidget::filePermissionsChanged(const QString &pFileName)
{
    // The given file has been un/locked, so enable/disable parts of our GUI,
    // should the given file be managed

    SingleCellViewSimulationWidget *simulationWidget = mSimulationWidgets.value(pFileName);

    if (simulationWidget)
        simulationWidget->filePermissionsChanged();
}

//==============================================================================

void SingleCellViewWidget::fileReloaded(const QString &pFileName)
{
    // The given file has been reloaded, so reload it, should it be managed

    if (contains(pFileName)) {
        finalize(pFileName);

        if (CellMLSupport::CellmlFileManager::instance()->isCellmlFile(pFileName))
            initialize(pFileName);
    }
}

//==============================================================================

void SingleCellViewWidget::fileRenamed(const QString &pOldFileName,
                                       const QString &pNewFileName)
{
    // The given file has been renamed, so update our simulating widgets mapping

    SingleCellViewSimulationWidget *simulationWidget = mSimulationWidgets.value(pOldFileName);

    if (simulationWidget) {
        mSimulationWidgets.insert(pNewFileName, simulationWidget);
        mSimulationWidgets.remove(pOldFileName);
    }
}

//==============================================================================

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Single Cell view: some work on making the view more file specific (#590) [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Single cell view widget
//==============================================================================

#include "cellmlfilemanager.h"
#include "singlecellviewsimulationwidget.h"
#include "singlecellviewwidget.h"

//==============================================================================

#include <QLayout>

//==============================================================================

namespace OpenCOR {
namespace SingleCellView {

//==============================================================================

SingleCellViewWidget::SingleCellViewWidget(SingleCellViewPlugin *pPlugin,
                                           QWidget *pParent) :
    ViewWidget(pParent),
    mPlugin(pPlugin),
    mSimulationWidget(0),
    mSimulationWidgets(QMap<QString, SingleCellViewSimulationWidget *>())
{
}

//==============================================================================

void SingleCellViewWidget::retranslateUi()
{
    // Retranslate our simulation widgets

    foreach (SingleCellViewSimulationWidget *simulationWidget, mSimulationWidgets)
        simulationWidget->retranslateUi();
}

//==============================================================================

bool SingleCellViewWidget::contains(const QString &pFileName) const
{
    // Return whether we know about the given file

    return mSimulationWidgets.contains(pFileName);
}

//==============================================================================

void SingleCellViewWidget::initialize(const QString &pFileName)
{
    // Retrieve the simulation widget associated with the given file, if any

    SingleCellViewSimulationWidget *oldSimulationWidget = mSimulationWidget;

    mSimulationWidget = mSimulationWidgets.value(pFileName);

    if (!mSimulationWidget) {
        // No simulation widget exists for the given file, so create one

        mSimulationWidget = new SingleCellViewSimulationWidget(mPlugin, this);

        // Keep track of our editing widget and add it to ourselves

        mSimulationWidgets.insert(pFileName, mSimulationWidget);

        layout()->addWidget(mSimulationWidget);
    }

    // Hide our previous simulation widget and show our new one

    mSimulationWidget->show();

    if (oldSimulationWidget && (mSimulationWidget != oldSimulationWidget))
        oldSimulationWidget->hide();

    // Set our focus proxy to our 'new' simulation widget and make sure that the
    // latter immediately gets the focus

    setFocusProxy(mSimulationWidget);

    mSimulationWidget->setFocus();
}

//==============================================================================

void SingleCellViewWidget::finalize(const QString &pFileName)
{
    // Remove the simulation widget, should there be one for the given file

    SingleCellViewSimulationWidget *simulationWidget = mSimulationWidgets.value(pFileName);

    if (simulationWidget) {
        // There is a simulation widget for the given file name, so delete it
        // and remove it from our list

        delete simulationWidget;

        mSimulationWidgets.remove(pFileName);

        // Reset our memory of the current editor, if needed

        if (simulationWidget == mSimulationWidget)
            mSimulationWidget = 0;
    }
}

//==============================================================================

void SingleCellViewWidget::filePermissionsChanged(const QString &pFileName)
{
    // The given file has been un/locked, so enable/disable parts of our GUI,
    // should the given file be managed

    SingleCellViewSimulationWidget *simulationWidget = mSimulationWidgets.value(pFileName);

    if (simulationWidget)
        simulationWidget->filePermissionsChanged();
}

//==============================================================================

void SingleCellViewWidget::fileReloaded(const QString &pFileName)
{
    // The given file has been reloaded, so reload it, should it be managed

    if (contains(pFileName)) {
        finalize(pFileName);

        if (CellMLSupport::CellmlFileManager::instance()->isCellmlFile(pFileName))
            initialize(pFileName);
    }
}

//==============================================================================

void SingleCellViewWidget::fileRenamed(const QString &pOldFileName,
                                       const QString &pNewFileName)
{
    // The given file has been renamed, so update our simulating widgets mapping

    SingleCellViewSimulationWidget *simulationWidget = mSimulationWidgets.value(pOldFileName);

    if (simulationWidget) {
        mSimulationWidgets.insert(pNewFileName, simulationWidget);
        mSimulationWidgets.remove(pOldFileName);
    }
}

//==============================================================================

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/
#include "condor_common.h"
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#if !defined(WIN32)
#include <netinet/in.h>
#endif

#include "condor_query.h"
#include "condor_attributes.h"
#include "condor_collector.h"
#include "condor_config.h"
#include "condor_network.h"
#include "condor_io.h"
#include "condor_parser.h"
#include "condor_adtypes.h"
#include "condor_debug.h"

#define XDR_ASSERT(x) {if (!(x)) return Q_COMMUNICATION_ERROR;}

char *new_strdup (const char *);

// The order and number of the elements of the following arrays *are*
// important.  (They follow the structure of the enumerations supplied
// in the header file condor_query.h)
const char *ScheddStringKeywords [] =
{
	ATTR_NAME
};

const char *ScheddIntegerKeywords [] =
{
	ATTR_NUM_USERS,
	ATTR_IDLE_JOBS,
	ATTR_RUNNING_JOBS
};

const char *ScheddFloatKeywords [] =
{
	""		// add null string to avoid compiler error
};

const char *StartdStringKeywords [] =
{
	ATTR_NAME,
	ATTR_MACHINE,
	ATTR_ARCH,
	ATTR_OPSYS
};

const char *StartdIntegerKeywords [] =
{
	ATTR_MEMORY,
	ATTR_DISK
};

const char *StartdFloatKeywords [] =
{
	""		// add null string to avoid compiler error
};

// normal ctor
CondorQuery::
CondorQuery (AdTypes qType)
{
	queryType = qType;
	switch (qType)
	{
	  case STARTD_AD:
		query.setNumStringCats (STARTD_STRING_THRESHOLD);
		query.setNumIntegerCats(STARTD_INT_THRESHOLD);
		query.setNumFloatCats  (STARTD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)StartdIntegerKeywords);
		query.setStringKwList  ((char **)StartdStringKeywords);
		query.setFloatKwList   ((char **)StartdFloatKeywords);
		command = QUERY_STARTD_ADS;
		break;

	  case STARTD_PVT_AD:
		query.setNumStringCats (STARTD_STRING_THRESHOLD);
		query.setNumIntegerCats(STARTD_INT_THRESHOLD);
		query.setNumFloatCats  (STARTD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)StartdIntegerKeywords);
		query.setStringKwList  ((char **)StartdStringKeywords);
		query.setFloatKwList   ((char **)StartdFloatKeywords);
		command = QUERY_STARTD_PVT_ADS;
		break;

	  case SCHEDD_AD:
		query.setNumStringCats (SCHEDD_STRING_THRESHOLD);
		query.setNumIntegerCats(SCHEDD_INT_THRESHOLD);
		query.setNumFloatCats  (SCHEDD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)ScheddIntegerKeywords);
		query.setStringKwList  ((char **)ScheddStringKeywords);
		query.setFloatKwList   ((char **)ScheddFloatKeywords);
		command = QUERY_SCHEDD_ADS;
		break;

	  case SUBMITTOR_AD:
		query.setNumStringCats (SCHEDD_STRING_THRESHOLD);
		query.setNumIntegerCats(SCHEDD_INT_THRESHOLD);
		query.setNumFloatCats  (SCHEDD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)ScheddIntegerKeywords);
		query.setStringKwList  ((char **)ScheddStringKeywords);
		query.setFloatKwList   ((char **)ScheddFloatKeywords);
		command = QUERY_SUBMITTOR_ADS;
		break;

	  case LICENSE_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_LICENSE_ADS;
		break;

	  case MASTER_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_MASTER_ADS;
		break;

	  case CKPT_SRVR_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_CKPT_SRVR_ADS;
		break;

	  case COLLECTOR_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_COLLECTOR_ADS;
		break;

	  default:
		command = -1;
		queryType = (AdTypes) -1;
	}
}

// copy ctor; makes deep copy
CondorQuery::
CondorQuery (const CondorQuery &from)
{
}

// dtor
CondorQuery::
~CondorQuery ()
{
}

// clear particular string category
QueryResult CondorQuery::
clearStringConstraints (const int i)
{
	return (QueryResult) query.clearString (i);
}

// clear particular integer category
QueryResult CondorQuery::
clearIntegerConstraints (const int i)
{
	return (QueryResult) query.clearInteger (i);
}

// clear particular float category
QueryResult CondorQuery::
clearFloatConstraints (const int i)
{
	return (QueryResult) query.clearFloat (i);
}

void CondorQuery::
clearCustomConstraints (void)
{
	query.clearCustom ();
}

// add a string constraint
QueryResult CondorQuery::
addConstraint (const int cat, const char *value)
{
	return (QueryResult) query.addString (cat, (char *) value);
}

// add an integer constraint
QueryResult CondorQuery::
addConstraint (const int cat, const int value)
{
	return (QueryResult) query.addInteger (cat, value);
}

// add a float constraint
QueryResult CondorQuery::
addConstraint (const int cat, const float value)
{
	return (QueryResult) query.addFloat (cat, value);
}

// add a custom constraint
QueryResult CondorQuery::
addConstraint (const char *value)
{
	return (QueryResult) query.addCustom ((char *) value);
}

// fetch all ads from the collector that satisfy the constraints
QueryResult CondorQuery::
fetchAds (ClassAdList &adList, const char *poolName)
{
    char        *pool;
	char		defaultPool[32];
    ReliSock    sock;
	int			more;
    QueryResult result;
    ClassAd     queryAd, *ad;

	// use current pool's collector if not specified
	if (poolName == NULL || poolName[0] == '\0')
	{
		if ((pool = param ("COLLECTOR_HOST")) == NULL)  {
			return Q_NO_COLLECTOR_HOST;
		}
		strcpy (defaultPool, pool);
		free (pool);
		pool = defaultPool;
	}
	else {
		// pool specified
		pool = (char *) poolName;
	}

	// make the query ad
	result = (QueryResult) query.makeQuery (queryAd);
	if (result != Q_OK) return result;

	// fix types
	queryAd.SetMyTypeName (QUERY_ADTYPE);
	switch (queryType) {
	  case STARTD_AD:
	  case STARTD_PVT_AD:
		queryAd.SetTargetTypeName (STARTD_ADTYPE);
		break;

	  case SCHEDD_AD:
	  case SUBMITTOR_AD:
		queryAd.SetTargetTypeName (SCHEDD_ADTYPE);
		break;

	  case LICENSE_AD:
		queryAd.SetTargetTypeName (LICENSE_ADTYPE);
		break;

	  case MASTER_AD:
		queryAd.SetTargetTypeName (MASTER_ADTYPE);
		break;

	  case CKPT_SRVR_AD:
		queryAd.SetTargetTypeName (CKPT_SRVR_ADTYPE);
		break;

	  case COLLECTOR_AD:
		queryAd.SetTargetTypeName (COLLECTOR_ADTYPE);
		break;

	  default:
		return Q_INVALID_QUERY;
	}

	// contact collector
	if (!sock.connect(pool, COLLECTOR_COMM_PORT)) {
        return Q_COMMUNICATION_ERROR;
    }

	// ship query
	sock.encode();
	if (!sock.code (command) || !queryAd.put (sock) || !sock.end_of_message()) {
		return Q_COMMUNICATION_ERROR;
	}

	// get result
	sock.decode ();
	more = 1;
	while (more)
	{
		if (!sock.code (more)) {
			sock.end_of_message();
			return Q_COMMUNICATION_ERROR;
		}
		if (more) {
			ad = new ClassAd;
			if (!ad->get (sock)) {
				sock.end_of_message();
				delete ad;
				return Q_COMMUNICATION_ERROR;
			}
			adList.Insert (ad);
		}
	}
	sock.end_of_message();

	// finalize
	sock.close ();

	return (Q_OK);
}

QueryResult CondorQuery::
getQueryAd (ClassAd &queryAd)
{
	QueryResult	result;

	result = (QueryResult) query.makeQuery (queryAd);
	if (result != Q_OK) return result;

	// fix types
	queryAd.SetMyTypeName (QUERY_ADTYPE);
	switch (queryType) {
	  case STARTD_AD:
	  case STARTD_PVT_AD:
		queryAd.SetTargetTypeName (STARTD_ADTYPE);
		break;

	  case SCHEDD_AD:
	  case SUBMITTOR_AD:
		queryAd.SetTargetTypeName (SCHEDD_ADTYPE);
		break;

	  case LICENSE_AD:
		queryAd.SetTargetTypeName (LICENSE_ADTYPE);
		break;

	  case MASTER_AD:
		queryAd.SetTargetTypeName (MASTER_ADTYPE);
		break;

	  case CKPT_SRVR_AD:
		queryAd.SetTargetTypeName (CKPT_SRVR_ADTYPE);
		break;

	  case COLLECTOR_AD:
		queryAd.SetTargetTypeName (COLLECTOR_ADTYPE);
		break;

	  default:
		return Q_INVALID_QUERY;
	}

	return Q_OK;
}

QueryResult CondorQuery::
filterAds (ClassAdList &in, ClassAdList &out)
{
	ClassAd queryAd, *candidate;
	QueryResult	result;

	// make the query ad
	result = (QueryResult) query.makeQuery (queryAd);
	if (result != Q_OK) return result;

	in.Open();
	while (candidate = (ClassAd *) in.Next())
    {
        // if a match occurs
		if ((*candidate) >= (queryAd)) out.Insert (candidate);
    }
    in.Close ();

	return Q_OK;
}

char *getStrQueryResult(QueryResult q)
{
	switch (q)
	{
    	case Q_OK:					return "ok";
    	case Q_INVALID_CATEGORY:	return "invalid category";
    	case Q_MEMORY_ERROR:		return "memory error";
    	case Q_PARSE_ERROR:			return "parse error";
	    case Q_COMMUNICATION_ERROR:	return "communication error";
	    case Q_INVALID_QUERY:		return "invalid query";
	    case Q_NO_COLLECTOR_HOST:	return "no COLLECTOR_HOST";
		default:
			return "unknown error";
	}
}
<commit_msg>+ Use get_collector_addr() instead of doing things manually. + Removed some system header files we don't need.<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/
#include "condor_common.h"
#include "condor_query.h"
#include "condor_attributes.h"
#include "condor_collector.h"
#include "condor_config.h"
#include "condor_network.h"
#include "condor_io.h"
#include "condor_parser.h"
#include "condor_adtypes.h"
#include "condor_debug.h"
#include "get_daemon_addr.h"

#define XDR_ASSERT(x) {if (!(x)) return Q_COMMUNICATION_ERROR;}

char *new_strdup (const char *);

// The order and number of the elements of the following arrays *are*
// important.  (They follow the structure of the enumerations supplied
// in the header file condor_query.h)
const char *ScheddStringKeywords [] =
{
	ATTR_NAME
};

const char *ScheddIntegerKeywords [] =
{
	ATTR_NUM_USERS,
	ATTR_IDLE_JOBS,
	ATTR_RUNNING_JOBS
};

const char *ScheddFloatKeywords [] =
{
	""		// add null string to avoid compiler error
};

const char *StartdStringKeywords [] =
{
	ATTR_NAME,
	ATTR_MACHINE,
	ATTR_ARCH,
	ATTR_OPSYS
};

const char *StartdIntegerKeywords [] =
{
	ATTR_MEMORY,
	ATTR_DISK
};

const char *StartdFloatKeywords [] =
{
	""		// add null string to avoid compiler error
};

// normal ctor
CondorQuery::
CondorQuery (AdTypes qType)
{
	queryType = qType;
	switch (qType)
	{
	  case STARTD_AD:
		query.setNumStringCats (STARTD_STRING_THRESHOLD);
		query.setNumIntegerCats(STARTD_INT_THRESHOLD);
		query.setNumFloatCats  (STARTD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)StartdIntegerKeywords);
		query.setStringKwList  ((char **)StartdStringKeywords);
		query.setFloatKwList   ((char **)StartdFloatKeywords);
		command = QUERY_STARTD_ADS;
		break;

	  case STARTD_PVT_AD:
		query.setNumStringCats (STARTD_STRING_THRESHOLD);
		query.setNumIntegerCats(STARTD_INT_THRESHOLD);
		query.setNumFloatCats  (STARTD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)StartdIntegerKeywords);
		query.setStringKwList  ((char **)StartdStringKeywords);
		query.setFloatKwList   ((char **)StartdFloatKeywords);
		command = QUERY_STARTD_PVT_ADS;
		break;

	  case SCHEDD_AD:
		query.setNumStringCats (SCHEDD_STRING_THRESHOLD);
		query.setNumIntegerCats(SCHEDD_INT_THRESHOLD);
		query.setNumFloatCats  (SCHEDD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)ScheddIntegerKeywords);
		query.setStringKwList  ((char **)ScheddStringKeywords);
		query.setFloatKwList   ((char **)ScheddFloatKeywords);
		command = QUERY_SCHEDD_ADS;
		break;

	  case SUBMITTOR_AD:
		query.setNumStringCats (SCHEDD_STRING_THRESHOLD);
		query.setNumIntegerCats(SCHEDD_INT_THRESHOLD);
		query.setNumFloatCats  (SCHEDD_FLOAT_THRESHOLD);
		query.setIntegerKwList ((char **)ScheddIntegerKeywords);
		query.setStringKwList  ((char **)ScheddStringKeywords);
		query.setFloatKwList   ((char **)ScheddFloatKeywords);
		command = QUERY_SUBMITTOR_ADS;
		break;

	  case LICENSE_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_LICENSE_ADS;
		break;

	  case MASTER_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_MASTER_ADS;
		break;

	  case CKPT_SRVR_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_CKPT_SRVR_ADS;
		break;

	  case COLLECTOR_AD:
		query.setNumStringCats (0);
		query.setNumIntegerCats(0);
		query.setNumFloatCats  (0);
		command = QUERY_COLLECTOR_ADS;
		break;

	  default:
		command = -1;
		queryType = (AdTypes) -1;
	}
}

// copy ctor; makes deep copy
CondorQuery::
CondorQuery (const CondorQuery &from)
{
}

// dtor
CondorQuery::
~CondorQuery ()
{
}

// clear particular string category
QueryResult CondorQuery::
clearStringConstraints (const int i)
{
	return (QueryResult) query.clearString (i);
}

// clear particular integer category
QueryResult CondorQuery::
clearIntegerConstraints (const int i)
{
	return (QueryResult) query.clearInteger (i);
}

// clear particular float category
QueryResult CondorQuery::
clearFloatConstraints (const int i)
{
	return (QueryResult) query.clearFloat (i);
}

void CondorQuery::
clearCustomConstraints (void)
{
	query.clearCustom ();
}

// add a string constraint
QueryResult CondorQuery::
addConstraint (const int cat, const char *value)
{
	return (QueryResult) query.addString (cat, (char *) value);
}

// add an integer constraint
QueryResult CondorQuery::
addConstraint (const int cat, const int value)
{
	return (QueryResult) query.addInteger (cat, value);
}

// add a float constraint
QueryResult CondorQuery::
addConstraint (const int cat, const float value)
{
	return (QueryResult) query.addFloat (cat, value);
}

// add a custom constraint
QueryResult CondorQuery::
addConstraint (const char *value)
{
	return (QueryResult) query.addCustom ((char *) value);
}

// fetch all ads from the collector that satisfy the constraints
QueryResult CondorQuery::
fetchAds (ClassAdList &adList, const char *poolName)
{
    char        *pool;
	char		defaultPool[32];
    ReliSock    sock;
	int			more;
    QueryResult result;
    ClassAd     queryAd, *ad;

		// This will return the correct addr for the local pool's
		// collector if poolName is NULL.
	pool = get_collector_addr( poolName );

	// make the query ad
	result = (QueryResult) query.makeQuery (queryAd);
	if (result != Q_OK) return result;

	// fix types
	queryAd.SetMyTypeName (QUERY_ADTYPE);
	switch (queryType) {
	  case STARTD_AD:
	  case STARTD_PVT_AD:
		queryAd.SetTargetTypeName (STARTD_ADTYPE);
		break;

	  case SCHEDD_AD:
	  case SUBMITTOR_AD:
		queryAd.SetTargetTypeName (SCHEDD_ADTYPE);
		break;

	  case LICENSE_AD:
		queryAd.SetTargetTypeName (LICENSE_ADTYPE);
		break;

	  case MASTER_AD:
		queryAd.SetTargetTypeName (MASTER_ADTYPE);
		break;

	  case CKPT_SRVR_AD:
		queryAd.SetTargetTypeName (CKPT_SRVR_ADTYPE);
		break;

	  case COLLECTOR_AD:
		queryAd.SetTargetTypeName (COLLECTOR_ADTYPE);
		break;

	  default:
		return Q_INVALID_QUERY;
	}

	// contact collector
	if (!sock.connect(pool, COLLECTOR_COMM_PORT)) {
        return Q_COMMUNICATION_ERROR;
    }

	// ship query
	sock.encode();
	if (!sock.code (command) || !queryAd.put (sock) || !sock.end_of_message()) {
		return Q_COMMUNICATION_ERROR;
	}

	// get result
	sock.decode ();
	more = 1;
	while (more)
	{
		if (!sock.code (more)) {
			sock.end_of_message();
			return Q_COMMUNICATION_ERROR;
		}
		if (more) {
			ad = new ClassAd;
			if (!ad->get (sock)) {
				sock.end_of_message();
				delete ad;
				return Q_COMMUNICATION_ERROR;
			}
			adList.Insert (ad);
		}
	}
	sock.end_of_message();

	// finalize
	sock.close ();

	return (Q_OK);
}

QueryResult CondorQuery::
getQueryAd (ClassAd &queryAd)
{
	QueryResult	result;

	result = (QueryResult) query.makeQuery (queryAd);
	if (result != Q_OK) return result;

	// fix types
	queryAd.SetMyTypeName (QUERY_ADTYPE);
	switch (queryType) {
	  case STARTD_AD:
	  case STARTD_PVT_AD:
		queryAd.SetTargetTypeName (STARTD_ADTYPE);
		break;

	  case SCHEDD_AD:
	  case SUBMITTOR_AD:
		queryAd.SetTargetTypeName (SCHEDD_ADTYPE);
		break;

	  case LICENSE_AD:
		queryAd.SetTargetTypeName (LICENSE_ADTYPE);
		break;

	  case MASTER_AD:
		queryAd.SetTargetTypeName (MASTER_ADTYPE);
		break;

	  case CKPT_SRVR_AD:
		queryAd.SetTargetTypeName (CKPT_SRVR_ADTYPE);
		break;

	  case COLLECTOR_AD:
		queryAd.SetTargetTypeName (COLLECTOR_ADTYPE);
		break;

	  default:
		return Q_INVALID_QUERY;
	}

	return Q_OK;
}

QueryResult CondorQuery::
filterAds (ClassAdList &in, ClassAdList &out)
{
	ClassAd queryAd, *candidate;
	QueryResult	result;

	// make the query ad
	result = (QueryResult) query.makeQuery (queryAd);
	if (result != Q_OK) return result;

	in.Open();
	while (candidate = (ClassAd *) in.Next())
    {
        // if a match occurs
		if ((*candidate) >= (queryAd)) out.Insert (candidate);
    }
    in.Close ();

	return Q_OK;
}

char *getStrQueryResult(QueryResult q)
{
	switch (q)
	{
    	case Q_OK:					return "ok";
    	case Q_INVALID_CATEGORY:	return "invalid category";
    	case Q_MEMORY_ERROR:		return "memory error";
    	case Q_PARSE_ERROR:			return "parse error";
	    case Q_COMMUNICATION_ERROR:	return "communication error";
	    case Q_INVALID_QUERY:		return "invalid query";
	    case Q_NO_COLLECTOR_HOST:	return "no COLLECTOR_HOST";
		default:
			return "unknown error";
	}
}
<|endoftext|>