<commit_before>/**
 * @file    reduction.hpp
 * @author  Patrick Flick <patrick.flick@gmail.com>
 * @brief   Reduction operations.
 *
 * TODO add Licence
 */

#ifndef MXX_REDUCTION_HPP
#define MXX_REDUCTION_HPP

#include <mpi.h>

#include <vector>
#include <iterator>
#include <limits>
#include <functional>
#include <mutex>
#include <atomic>

// mxx includes
#include "datatypes.hpp"
#include "comm.hpp"

namespace mxx {

/*
 * Add any (key,value) pair to any MPI_Datatype using MPI caching (keyval)
 * functionality (used internally to mxx for adding std::function objects to
 * MPI datatypes, required for custom operators)
 */
template <typename K, typename T>
class attr_map {
private:
    // static "variables" wrapped into static member functions
    static int& key(){ static int k=0; return k; }
    static std::mutex& mut(){ static std::mutex m; return m; }
    static std::map<K, int>& keymap(){ static std::map<K, int> m; return m; }

    static int copy_attr(MPI_Datatype, int, void*, void *attribute_val_in, void *attribute_val_out, int *flag) {
        T** out = (T**) attribute_val_out;
        // copy via copy constructor
        *out = new T(*(T*)(attribute_val_in));
        *flag = 1;
        return MPI_SUCCESS;
    }

    static int del_attr(MPI_Datatype, int, void *attribute_val, void *) {
        delete (T*)attribute_val;
        return MPI_SUCCESS;
    }
public:
    static void set(const MPI_Datatype& dt, const K& k, const T& value) {
        std::lock_guard<std::mutex> lock(mut());
        if (keymap().find(k) == keymap().end()) {
            // create new keyval with MPI
            keymap()[k] = 0;
            MPI_Type_create_keyval(&attr_map<K,T>::copy_attr,
                                   &attr_map<K,T>::del_attr,
                                   &(keymap()[k]), (void*)NULL);
        }
        // insert new key into keymap
        // set the keyval pair
        T* val = new T(value); // copy construct
        MPI_Type_set_attr(dt, keymap()[k], (void*)val);
    }
    static T& get(const MPI_Datatype& dt, const K& k) {
        std::lock_guard<std::mutex> lock(mut());
        if (keymap().find(k) == keymap().end()) {
            throw std::out_of_range("Key not mapped.");
        }
        int key = keymap()[k];
        T* result;
        int flag;
        MPI_Type_get_attr(dt, key, &result, &flag);
        if (!flag) {
            throw std::out_of_range("Key not mapped.");
        }
        return *result;
    }
};

/*********************************************************************
 *                     User supplied functions:                      *
 *********************************************************************/

// an Op is not built-in in general:
template <typename T, typename Func>
struct get_builtin_op {
    static MPI_Op op(Func) {
        return MPI_OP_NULL;
    }
};

// define all C++ functors that map to a MPI builtin MPI_Op to directly map
// to that builtin MPI_Op
#define MXX_BUILTIN_OP(mpi_op, cpp_functor)                                    \
template <typename T>                                                          \
struct get_builtin_op<T, cpp_functor<T> > {                                      \
    static MPI_Op op(cpp_functor<T>) {                                           \
        return mpi_op;                                                        \
    }                                                                          \
};                                                                             \

MXX_BUILTIN_OP(MPI_SUM, std::plus);
MXX_BUILTIN_OP(MPI_PROD, std::multiplies);
MXX_BUILTIN_OP(MPI_LAND, std::logical_and);
MXX_BUILTIN_OP(MPI_LOR, std::logical_or);
MXX_BUILTIN_OP(MPI_BOR, std::bit_or);
MXX_BUILTIN_OP(MPI_BXOR, std::bit_xor);
MXX_BUILTIN_OP(MPI_BAND, std::bit_and);

#undef MXX_BUILTIN_OP

// for std::min/std::max functions
template <typename T>
struct get_builtin_op<T, const T&(*) (const T&, const T&)> {
    static MPI_Op op(const T& (*t)(const T&, const T&)) {
        // check if function is std::min or std::max
        if (t == static_cast<const T&(*)(const T&, const T&)>(std::min<T>)){
            return MPI_MIN;
        } else if (t == static_cast<const T&(*)(const T&, const T&)>(std::max<T>)){
            return MPI_MAX;
        } else {
            // otherwise return NULL
            return MPI_OP_NULL;
        }
    }
};

/**
 * @brief   Wrapps a binary combination/reduction operator for MPI use in
 *          custom operators.
 *
 * @note    This assumes that the operator is commutative.
 *
 * @tparam T    The input and ouput datatype of the binary operator.
 * @tparam IsCommutative    Whether or not the operation is commutative (default = true).
 */
template <typename T, bool IsCommutative = true>
class custom_op {
public:

    /**
     * @brief Creates a custom operator given a functor and the associated
     *        `MPI_Datatype`.
     *
     * @tparam Func     Type of the functor, can be a function pointer, lambda
     *                  function, or std::function or any object with a
     *                  `T operator(T& x, T& y)` member.
     * @param func      The instance of the functor.
     */
    template <typename Func>
    custom_op(Func func) : builtin(false) {
        if (mxx::is_builtin_type<T>::value) {
            // check if the operator is MPI built-in (in case the type
            // is also a MPI built-in type)
            MPI_Op o = get_builtin_op<T, Func>::op(std::forward<Func>(func));
            if (o != MPI_OP_NULL) {
                // this op is builtin, save it as such and don't copy built-in type
                builtin = true;
                op = o;
                mxx::datatype<T> dt;
                type_copy = dt.type();
            }
        }
        if (!builtin) {
            // create user function
            using namespace std::placeholders;
            user_func = std::bind(custom_op::custom_function<Func>, std::forward<Func>(func), _1, _2, _3);
            // get datatype associated with the type `T`
            mxx::datatype<T> dt;
            // attach function to a copy of the datatype
            MPI_Type_dup(dt.type(), &type_copy);
            attr_map<int, func_t>::set(type_copy, 1347, user_func);
            // create op
            MPI_Op_create(&custom_op::mpi_user_function, IsCommutative, &op);
        }
    }

    /**
     * @brief   Returns the MPI_Datatype which has to be used in conjuction
     *          with the MPI_Op operator.
     *
     * The custom operators are wrapped into `std::function` objects and
     * saved/attached to a duplicated MPI_Datatype as MPI attribute.
     *
     * When MPI calls the custom user function, the MPI_Datatype is supplied
     * and thus the `std::function` object can be accessed and executed.
     *
     * @returns The `MPI_Datatype` which has to be used in conjuction with the
     *          `MPI_Op` returned by `get_op()` for all MPI reduction operations.
     */
    MPI_Datatype get_type() const {
        return type_copy;
    }

    /**
     * @brief   Returns the `MPI_Op` operator for reduction operations.
     *
     * @note
     * The MPI operator `MPI_Op` returned by this function can only be used in
     * conjunction with the `MPI_Datatype` returned by `get_type()`.
     *
     * @returns     The MPI operator as `MPI_Op` object.
     */
    MPI_Op get_op() const {
        return op;
    }

    /// Destructor: cleanup MPI objects
    virtual ~custom_op() {
        if (!builtin) {
            // clean-up (only if this wasn't a built-in MPI_Op)
            MPI_Op_free(&op);
            MPI_Type_free(&type_copy);
        }
    }
private:
    // Apply the user provided function to all elements passed by MPI.
    // The user provided function (lambda, function pointer, functor)
    // is bound to this function via std::bind, and the resulting object
    // saved in the MPI_Datatype
    template <typename Func>
    static void custom_function(Func func, void* invec, void* inoutvec, int* len) {
        T* in = (T*) invec;
        T* inout = (T*) inoutvec;
        for (int i = 0; i < *len; ++i) {
            inout[i] = func(in[i], inout[i]);
        }
    }
    // MPI custom Op function: (of type MPI_User_function)
    // This function is called from within MPI
    static void mpi_user_function(void* in, void* inout, int* n, MPI_Datatype* dt) {
        // get the std::function from the MPI_Datatype and call it
        typedef std::function<void(void*,void*,int*)> func_t;
        func_t f = attr_map<int, func_t>::get(*dt, 1347);
        f(in, inout, n);
    }

    // the std::function user function wrapper, which is called from the mpi user function
    typedef std::function<void(void*,void*,int*)> func_t;
    func_t user_func;
    /// Whether the MPI_Op is a builtin operator (e.g. MPI_SUM)
    bool builtin;
    /// The copy (Type_dup) of the MPI_Datatype to work on
    MPI_Datatype type_copy;
    /// The MPI user operator
    MPI_Op op;
};

/*********************************************************************
 *                Reductions                                         *
 *********************************************************************/
// TODO: add more (vectorized (std::vector, [begin,end),...), different reduce ops, etc)
// TODO: naming of functions !?
// TODO: come up with good naming scheme and standardize!
// TODO: template specialize for std::min, std::max, std::plus, std::multiply
//       etc for integers to use MPI builtin ops?

template <typename T, typename Func>
T reduce(const T& x, int root, Func func, const mxx::comm& comm = mxx::comm()) {
    // get custom op (and type for custom op)
    mxx::custom_op<T> op(std::forward<Func>(func));
    T result = T();
    MPI_Reduce(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), root, comm);
    return result;
}

template <typename T>
T reduce(const T& x, int root, const mxx::comm& comm = mxx::comm()) {
    return reduce(x, root, std::plus<T>(), comm);
}

// TODO: vectorized ops

template <typename T, typename Func>
T allreduce(const T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    // get custom op (and type for custom op)
    mxx::custom_op<T> op(std::forward<Func>(func));
    // perform reduction
    T result;
    MPI_Allreduce(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), comm);
    return result;
}

template <typename T>
T allreduce(const T& x, const mxx::comm& comm = mxx::comm()) {
    return allreduce(x, std::plus<T>(), comm);
}

template <typename T, typename Func>
T scan(const T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    // get op
    mxx::custom_op<T> op(std::forward<Func>(func));
    T result;
    MPI_Scan(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), comm);
    return result;
}
template <typename T>
T scan(const T& x, const mxx::comm& comm = mxx::comm()) {
    return scan(x, std::plus<T>(), comm);
}

template <typename T, typename Func>
T exscan(const T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    // get op
    mxx::custom_op<T> op(std::forward<Func>(func));
    // perform reduction
    T result;
    MPI_Exscan(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), comm);
    if (comm.rank() == 0)
      result = T();
    return result;
}

template <typename T>
T exscan(const T& x, const mxx::comm& comm = mxx::comm()) {
    return exscan(x, std::plus<T>(), comm);
}

/****************************************************
 *  reverse reductions (with reverse communicator)  *
 ****************************************************/

inline void rev_comm(MPI_Comm comm, MPI_Comm& rev)
{
    // get MPI parameters
    int rank;
    int p;
    MPI_Comm_rank(comm, &rank);
    MPI_Comm_size(comm, &p);
    MPI_Comm_split(comm, 0, p - rank, &rev);
}

template <typename T>
T reverse_exscan(T& x, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = exscan(x, rev);
    MPI_Comm_free(&rev);
    return result;
}

template <typename T, typename Func>
T reverse_exscan(T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = exscan(x, func, rev);
    MPI_Comm_free(&rev);
    return result;
}

template <typename T>
T reverse_scan(T& x, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = scan(x, rev);
    MPI_Comm_free(&rev);
    return result;
}

template <typename T, typename Func>
T reverse_scan(T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = scan(x, func, rev);
    MPI_Comm_free(&rev);
    return result;
}

/*********************
 *  Specialized ops  *
 *********************/

/************************
 *  Boolean reductions  *
 ************************/
// useful for testing global conditions, such as termination conditions

inline bool all_of(bool x, const mxx::comm& comm = mxx::comm()) {
    int i = x ? 1 : 0;
    int result;
    MPI_Allreduce(&i, &result, 1, MPI_INT, MPI_LAND, comm);
    return result != 0;
}

inline bool any_of(bool x, const mxx::comm& comm = mxx::comm()) {
    int i = x ? 1 : 0;
    int result;
    MPI_Allreduce(&i, &result, 1, MPI_INT, MPI_LOR, comm);
    return result != 0;
}

inline bool none_of(bool x, const mxx::comm& comm = mxx::comm()) {
    int i = x ? 1 : 0;
    int result;
    MPI_Allreduce(&i, &result, 1, MPI_INT, MPI_LAND, comm);
    return result == 0;
}

} // namespace mxx

#endif // MXX_REDUCTION_HPP
<commit_msg>cleanup<commit_after>/**
 * @file    reduction.hpp
 * @author  Patrick Flick <patrick.flick@gmail.com>
 * @brief   Reduction operations.
 *
 * TODO add Licence
 */

#ifndef MXX_REDUCTION_HPP
#define MXX_REDUCTION_HPP

#include <mpi.h>

#include <vector>
#include <iterator>
#include <limits>
#include <functional>
#include <mutex>
#include <atomic>

// mxx includes
#include "datatypes.hpp"
#include "comm.hpp"

namespace mxx {

/*
 * Add any (key,value) pair to any MPI_Datatype using MPI caching (keyval)
 * functionality (used internally to mxx for adding std::function objects to
 * MPI datatypes, required for custom operators)
 */
template <typename K, typename T>
class attr_map {
private:
    // static "variables" wrapped into static member functions
    static int& key(){ static int k=0; return k; }
    static std::mutex& mut(){ static std::mutex m; return m; }
    static std::map<K, int>& keymap(){ static std::map<K, int> m; return m; }

    static int copy_attr(MPI_Datatype, int, void*, void *attribute_val_in, void *attribute_val_out, int *flag) {
        T** out = (T**) attribute_val_out;
        // copy via copy constructor
        *out = new T(*(T*)(attribute_val_in));
        *flag = 1;
        return MPI_SUCCESS;
    }

    static int del_attr(MPI_Datatype, int, void *attribute_val, void *) {
        delete (T*)attribute_val;
        return MPI_SUCCESS;
    }
public:
    static void set(const MPI_Datatype& dt, const K& k, const T& value) {
        std::lock_guard<std::mutex> lock(mut());
        if (keymap().find(k) == keymap().end()) {
            // create new keyval with MPI
            keymap()[k] = 0;
            MPI_Type_create_keyval(&attr_map<K,T>::copy_attr,
                                   &attr_map<K,T>::del_attr,
                                   &(keymap()[k]), (void*)NULL);
        }
        // insert new key into keymap
        // set the keyval pair
        T* val = new T(value); // copy construct
        MPI_Type_set_attr(dt, keymap()[k], (void*)val);
    }
    static T& get(const MPI_Datatype& dt, const K& k) {
        std::lock_guard<std::mutex> lock(mut());
        if (keymap().find(k) == keymap().end()) {
            throw std::out_of_range("Key not mapped.");
        }
        int key = keymap()[k];
        T* result;
        int flag;
        MPI_Type_get_attr(dt, key, &result, &flag);
        if (!flag) {
            throw std::out_of_range("Key not mapped.");
        }
        return *result;
    }
};

/*********************************************************************
 *                     User supplied functions:                      *
 *********************************************************************/

// an Op is not built-in in general:
template <typename T, typename Func>
struct get_builtin_op {
    static MPI_Op op(Func) {
        return MPI_OP_NULL;
    }
};

// define all C++ functors that map to a MPI builtin MPI_Op to directly map
// to that builtin MPI_Op
#define MXX_BUILTIN_OP(mpi_op, cpp_functor)                                    \
template <typename T>                                                          \
struct get_builtin_op<T, cpp_functor<T> > {                                    \
    static MPI_Op op(cpp_functor<T>) {                                         \
        return mpi_op;                                                         \
    }                                                                          \
};                                                                             \

MXX_BUILTIN_OP(MPI_SUM, std::plus);
MXX_BUILTIN_OP(MPI_PROD, std::multiplies);
MXX_BUILTIN_OP(MPI_LAND, std::logical_and);
MXX_BUILTIN_OP(MPI_LOR, std::logical_or);
MXX_BUILTIN_OP(MPI_BOR, std::bit_or);
MXX_BUILTIN_OP(MPI_BXOR, std::bit_xor);
MXX_BUILTIN_OP(MPI_BAND, std::bit_and);

#undef MXX_BUILTIN_OP

// for std::min/std::max functions
template <typename T>
struct get_builtin_op<T, const T&(*) (const T&, const T&)> {
    static MPI_Op op(const T& (*t)(const T&, const T&)) {
        // check if function is std::min or std::max
        if (t == static_cast<const T&(*)(const T&, const T&)>(std::min<T>)){
            return MPI_MIN;
        } else if (t == static_cast<const T&(*)(const T&, const T&)>(std::max<T>)){
            return MPI_MAX;
        } else {
            // otherwise return NULL
            return MPI_OP_NULL;
        }
    }
};

/**
 * @brief   Wrapps a binary combination/reduction operator for MPI use in
 *          custom operators.
 *
 * @note    This assumes that the operator is commutative.
 *
 * @tparam T    The input and ouput datatype of the binary operator.
 * @tparam IsCommutative    Whether or not the operation is commutative (default = true).
 */
template <typename T, bool IsCommutative = true>
class custom_op {
public:

    /**
     * @brief Creates a custom operator given a functor and the associated
     *        `MPI_Datatype`.
     *
     * @tparam Func     Type of the functor, can be a function pointer, lambda
     *                  function, or std::function or any object with a
     *                  `T operator(T& x, T& y)` member.
     * @param func      The instance of the functor.
     */
    template <typename Func>
    custom_op(Func func) : m_builtin(false) {
        if (mxx::is_builtin_type<T>::value) {
            // check if the operator is MPI built-in (in case the type
            // is also a MPI built-in type)
            MPI_Op op = get_builtin_op<T, Func>::op(std::forward<Func>(func));
            if (op != MPI_OP_NULL) {
                // this op is builtin, save it as such and don't copy built-in type
                m_builtin = true;
                m_op = op;
                mxx::datatype<T> dt;
                m_type_copy = dt.type();
            }
        }
        if (!m_builtin) {
            // create user function
            using namespace std::placeholders;
            m_user_func = std::bind(custom_op::custom_function<Func>,
                                  std::forward<Func>(func), _1, _2, _3);
            // get datatype associated with the type `T`
            mxx::datatype<T> dt;
            // attach function to a copy of the datatype
            MPI_Type_dup(dt.type(), &m_type_copy);
            attr_map<int, func_t>::set(m_type_copy, 1347, m_user_func);
            // create op
            MPI_Op_create(&custom_op::mpi_user_function, IsCommutative, &m_op);
        }
    }

    /**
     * @brief   Returns the MPI_Datatype which has to be used in conjuction
     *          with the MPI_Op operator.
     *
     * The custom operators are wrapped into `std::function` objects and
     * saved/attached to a duplicated MPI_Datatype as MPI attribute.
     *
     * When MPI calls the custom user function, the MPI_Datatype is supplied
     * and thus the `std::function` object can be accessed and executed.
     *
     * @returns The `MPI_Datatype` which has to be used in conjuction with the
     *          `MPI_Op` returned by `get_op()` for all MPI reduction operations.
     */
    MPI_Datatype get_type() const {
        return m_type_copy;
    }

    /**
     * @brief   Returns the `MPI_Op` operator for reduction operations.
     *
     * @note
     * The MPI operator `MPI_Op` returned by this function can only be used in
     * conjunction with the `MPI_Datatype` returned by `get_type()`.
     *
     * @returns     The MPI operator as `MPI_Op` object.
     */
    MPI_Op get_op() const {
        return m_op;
    }

    /// Destructor: cleanup MPI objects
    virtual ~custom_op() {
        if (!m_builtin) {
            // clean-up (only if this wasn't a built-in MPI_Op)
            MPI_Op_free(&m_op);
            MPI_Type_free(&m_type_copy);
        }
    }
private:
    // Apply the user provided function to all elements passed by MPI.
    // The user provided function (lambda, function pointer, functor)
    // is bound to this function via std::bind, and the resulting object
    // saved in the MPI_Datatype
    template <typename Func>
    static void custom_function(Func func, void* invec, void* inoutvec, int* len) {
        T* in = (T*) invec;
        T* inout = (T*) inoutvec;
        for (int i = 0; i < *len; ++i) {
            inout[i] = func(in[i], inout[i]);
        }
    }
    // MPI custom Op function: (of type MPI_User_function)
    // This function is called from within MPI
    static void mpi_user_function(void* in, void* inout, int* n, MPI_Datatype* dt) {
        // get the std::function from the MPI_Datatype and call it
        typedef std::function<void(void*,void*,int*)> func_t;
        func_t f = attr_map<int, func_t>::get(*dt, 1347);
        f(in, inout, n);
    }

    // the std::function user function wrapper, which is called from the mpi user function
    typedef std::function<void(void*,void*,int*)> func_t;
    func_t m_user_func;
    /// Whether the MPI_Op is a builtin operator (e.g. MPI_SUM)
    bool m_builtin;
    /// The copy (Type_dup) of the MPI_Datatype to work on
    MPI_Datatype m_type_copy;
    /// The MPI user operator
    MPI_Op m_op;
};

/*********************************************************************
 *                Reductions                                         *
 *********************************************************************/
// TODO: add more (vectorized (std::vector, [begin,end),...), different reduce ops, etc)
// TODO: naming of functions !?
// TODO: come up with good naming scheme and standardize!

template <typename T, typename Func>
void reduce(const T* in, size_t n, const T* out, int root, Func func, const mxx::comm& comm = mxx::comm()) {

}

template <typename T, typename Func>
T reduce(const T& x, int root, Func func, const mxx::comm& comm = mxx::comm()) {
    // get custom op (and type for custom op)
    mxx::custom_op<T> op(std::forward<Func>(func));
    T result = T();
    MPI_Reduce(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), root, comm);
    return result;
}

template <typename T>
T reduce(const T& x, int root, const mxx::comm& comm = mxx::comm()) {
    return reduce(x, root, std::plus<T>(), comm);
}

// TODO: vectorized ops

template <typename T, typename Func>
T allreduce(const T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    // get custom op (and type for custom op)
    mxx::custom_op<T> op(std::forward<Func>(func));
    // perform reduction
    T result;
    MPI_Allreduce(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), comm);
    return result;
}

template <typename T>
T allreduce(const T& x, const mxx::comm& comm = mxx::comm()) {
    return allreduce(x, std::plus<T>(), comm);
}

template <typename T, typename Func>
T scan(const T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    // get op
    mxx::custom_op<T> op(std::forward<Func>(func));
    T result;
    MPI_Scan(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), comm);
    return result;
}
template <typename T>
T scan(const T& x, const mxx::comm& comm = mxx::comm()) {
    return scan(x, std::plus<T>(), comm);
}

template <typename T, typename Func>
T exscan(const T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    // get op
    mxx::custom_op<T> op(std::forward<Func>(func));
    // perform reduction
    T result;
    MPI_Exscan(const_cast<T*>(&x), &result, 1, op.get_type(), op.get_op(), comm);
    if (comm.rank() == 0)
      result = T();
    return result;
}

template <typename T>
T exscan(const T& x, const mxx::comm& comm = mxx::comm()) {
    return exscan(x, std::plus<T>(), comm);
}

/****************************************************
 *  reverse reductions (with reverse communicator)  *
 ****************************************************/

inline void rev_comm(MPI_Comm comm, MPI_Comm& rev)
{
    // get MPI parameters
    int rank;
    int p;
    MPI_Comm_rank(comm, &rank);
    MPI_Comm_size(comm, &p);
    MPI_Comm_split(comm, 0, p - rank, &rev);
}

template <typename T>
T reverse_exscan(T& x, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = exscan(x, rev);
    MPI_Comm_free(&rev);
    return result;
}

template <typename T, typename Func>
T reverse_exscan(T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = exscan(x, func, rev);
    MPI_Comm_free(&rev);
    return result;
}

template <typename T>
T reverse_scan(T& x, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = scan(x, rev);
    MPI_Comm_free(&rev);
    return result;
}

template <typename T, typename Func>
T reverse_scan(T& x, Func func, const mxx::comm& comm = mxx::comm()) {
    MPI_Comm rev;
    rev_comm(comm, rev);
    T result = scan(x, func, rev);
    MPI_Comm_free(&rev);
    return result;
}

/*********************
 *  Specialized ops  *
 *********************/

/************************
 *  Boolean reductions  *
 ************************/
// useful for testing global conditions, such as termination conditions

inline bool all_of(bool x, const mxx::comm& comm = mxx::comm()) {
    int i = x ? 1 : 0;
    int result;
    MPI_Allreduce(&i, &result, 1, MPI_INT, MPI_LAND, comm);
    return result != 0;
}

inline bool any_of(bool x, const mxx::comm& comm = mxx::comm()) {
    int i = x ? 1 : 0;
    int result;
    MPI_Allreduce(&i, &result, 1, MPI_INT, MPI_LOR, comm);
    return result != 0;
}

inline bool none_of(bool x, const mxx::comm& comm = mxx::comm()) {
    int i = x ? 1 : 0;
    int result;
    MPI_Allreduce(&i, &result, 1, MPI_INT, MPI_LAND, comm);
    return result == 0;
}

} // namespace mxx

#endif // MXX_REDUCTION_HPP
<|endoftext|>


<commit_before>#ifndef NN_LSTM_HPP
#define NN_LSTM_HPP

#include "linear.hpp"
#include "logistic.hpp"
#include "tanh.hpp"

namespace nnlib
{

template <typename T>
class LSTM;

template <typename T>
void swap(LSTM<T> &, LSTM<T> &);

/// \brief Long short-term memory recurrent module.
///
/// This implementation makes a strong assumption that inputs and outputs are matrices.
template <typename T = double>
class LSTM : public Module<T>
{
public:
	LSTM(size_t inps, size_t outs);
	LSTM(const LSTM &module);
	LSTM(const Serialized &node);

	virtual ~LSTM();

	LSTM &operator=(LSTM module);

	friend void swap(LSTM &a, LSTM &b);

	LSTM &gradClip(T clip);
	T gradClip() const;

	virtual void forget() override;
	virtual void save(Serialized &node) const override;

	virtual Tensor<T> &forward(const Tensor<T> &input) override;
	virtual Tensor<T> &backward(const Tensor<T> &input, const Tensor<T> &outGrad) override;

	virtual Storage<Tensor<T> *> paramsList() override;
	virtual Storage<Tensor<T> *> gradList() override;
	virtual Storage<Tensor<T> *> stateList() override;

protected:
	using Module<T>::m_output;
	using Module<T>::m_inGrad;

private:
	Module<T> *m_inpGateX;
	Module<T> *m_inpGateY;
	Module<T> *m_inpGateH;
	Module<T> *m_inpGate;
	Module<T> *m_fgtGateX;
	Module<T> *m_fgtGateY;
	Module<T> *m_fgtGateH;
	Module<T> *m_fgtGate;
	Module<T> *m_inpModX;
	Module<T> *m_inpModY;
	Module<T> *m_inpMod;
	Module<T> *m_outGateX;
	Module<T> *m_outGateY;
	Module<T> *m_outGateH;
	Module<T> *m_outGate;
	Module<T> *m_outMod;

	Tensor<T> m_inpAdd;
	Tensor<T> m_fgtAdd;
	Tensor<T> m_outGrad;

	Tensor<T> m_state;
	Tensor<T> m_prevState;
	Tensor<T> m_prevOutput;
	Tensor<T> m_stateGrad;
	Tensor<T> m_curStateGrad;
	Tensor<T> m_gradBuffer;

	T m_clip;
	size_t m_outs;
};

}

NNRegisterType(LSTM, Module);
NNTemplateDefinition(LSTM, "detail/lstm.tpp");

#endif
<commit_msg>Split LSTM.<commit_after>#ifndef NN_LSTM_HPP
#define NN_LSTM_HPP

#include "linear.hpp"
#include "logistic.hpp"
#include "tanh.hpp"

namespace nnlib
{

template <typename T>
class LSTM;

template <typename T>
void swap(LSTM<T> &, LSTM<T> &);

/// \brief Long short-term memory recurrent module.
///
/// This implementation makes a strong assumption that inputs and outputs are matrices.
template <typename T = double>
class LSTM : public Module<T>
{
public:
	LSTM(size_t inps, size_t outs);
	LSTM(const LSTM &module);
	LSTM(const Serialized &node);

	virtual ~LSTM();

	LSTM &operator=(LSTM module);

	friend void swap <> (LSTM &a, LSTM &b);

	LSTM &gradClip(T clip);
	T gradClip() const;

	virtual void forget() override;
	virtual void save(Serialized &node) const override;

	virtual Tensor<T> &forward(const Tensor<T> &input) override;
	virtual Tensor<T> &backward(const Tensor<T> &input, const Tensor<T> &outGrad) override;

	virtual Storage<Tensor<T> *> paramsList() override;
	virtual Storage<Tensor<T> *> gradList() override;
	virtual Storage<Tensor<T> *> stateList() override;

protected:
	using Module<T>::m_output;
	using Module<T>::m_inGrad;

private:
	Module<T> *m_inpGateX;
	Module<T> *m_inpGateY;
	Module<T> *m_inpGateH;
	Module<T> *m_inpGate;
	Module<T> *m_fgtGateX;
	Module<T> *m_fgtGateY;
	Module<T> *m_fgtGateH;
	Module<T> *m_fgtGate;
	Module<T> *m_inpModX;
	Module<T> *m_inpModY;
	Module<T> *m_inpMod;
	Module<T> *m_outGateX;
	Module<T> *m_outGateY;
	Module<T> *m_outGateH;
	Module<T> *m_outGate;
	Module<T> *m_outMod;

	Tensor<T> m_inpAdd;
	Tensor<T> m_fgtAdd;
	Tensor<T> m_outGrad;

	Tensor<T> m_state;
	Tensor<T> m_prevState;
	Tensor<T> m_prevOutput;
	Tensor<T> m_stateGrad;
	Tensor<T> m_curStateGrad;
	Tensor<T> m_gradBuffer;

	T m_clip;
	size_t m_outs;
};

}

NNRegisterType(LSTM, Module);
NNTemplateDefinition(LSTM, "detail/lstm.tpp");

#endif
<|endoftext|>


<commit_before>// Source file for the surfel labeler program

////////////////////////////////////////////////////////////////////////
// Include files
////////////////////////////////////////////////////////////////////////

namespace gaps {}
using namespace gaps;
#include "R3Utils/R3Utils.h"
#include "io.h"
#include "ui.h"

////////////////////////////////////////////////////////////////////////
// Program arguments
////////////////////////////////////////////////////////////////////////

static const char *scene_filename = NULL;
static const char *database_filename = NULL;
static const char *input_pixel_database_filename = NULL;
static const char *input_image_directory = NULL;
static const char *output_history_filename = NULL;
static const char *output_snapshot_directory = NULL;
static double depth_scale = 2000;
static double depth_exponent = 0.5;
static int multiresolution = 0;
static int dynamic_cache = 0;
static int max_images = 0;
static int apply_may2022_scene_updates = 0;
static int print_verbose = 0;

///////////////////////////////////////////////////////////////////////
// Apply temporary scene modifications
////////////////////////////////////////////////////////////////////////

static int
AddLabel(R3SurfelScene *scene, const char *name,
  int identifier, int assignment_key,
  int r, int g, int b, const char *parent_name = NULL)
{
  // Check stuff
  if (!scene) return 0;
  if (!name) return 0;

  // Check if label already exists
  if (scene->FindLabelByName(name)) return 1;

  // Find parent label
  R3SurfelLabel *parent = scene->RootLabel();
  if (parent_name) parent = scene->FindLabelByName(parent_name);
  if (!parent) return 0;

  // Create label
  R3SurfelLabel *label =  new R3SurfelLabel(name);
  label->SetColor(gaps::RNRgb(r / 255.0, g / 255.0, b / 255.0));
  label->SetIdentifier(identifier);
  label->SetAssignmentKeystroke(assignment_key);
  scene->InsertLabel(label, parent);

  // Return success
  return 1;
}

static int
AddLabelFlags(R3SurfelScene *scene, const char *label_name, RNFlags flags)
{
  // Find label
  R3SurfelLabel *label = scene->FindLabelByName(label_name);
  if (!label) return 0;

  // Update label flags
  RNFlags label_flags = label->Flags();
  label_flags.Add(flags);
  label->SetFlags(label_flags);

  // Return success
  return 1;
}

static int
SetLabelAssignmentKey(R3SurfelScene *scene, const char *label_name, int assignment_key)
{
  // Find label
  R3SurfelLabel *label = scene->FindLabelByName(label_name);
  if (!label) return 0;

  // Update assignment key
  label->SetAssignmentKeystroke(assignment_key);

  // Return success
  return 1;
}

static void
ApplyMay2022SceneUpdates(R3SurfelScene *scene)
{
  // Reset label assignment keys
  SetLabelAssignmentKey(scene, "OtherVehicle", 'C');

  // Add new labels
  const int PEDESTRIAN_ENTRANCE_LABEL = 47;
  const int VEHICLE_ENTRANCE_LABEL = 48;
  AddLabel(scene, "PedestrianEntrance", PEDESTRIAN_ENTRANCE_LABEL, 'n', 240, 140, 140);
  AddLabel(scene, "VehicleEntrance", VEHICLE_ENTRANCE_LABEL, 'v', 240, 0, 240);

  // Add label axis flags
  AddLabelFlags(scene, "Billboard", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "BusinessSign", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "PedestrianEntrance", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "TempTrafficSign", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "TrafficSign", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "VehicleEntrance", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);

  // Add label unorientable flags
  AddLabelFlags(scene, "Bridge", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "BuildingInterior", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "BuildingExterior", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "BusStop", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Crosswalk", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Driveway", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Fence", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "FireHydrant", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "GuardRail", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "LidarArtifact", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Mountain", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherGround", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherPermanentObject", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherStructure", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherTempObject", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "ParkingMeter", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "PavedRoad", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Pole", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Self", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Sidewalk", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Sky", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "StreetLight", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "TempCone", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Terrain", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Tree", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Tunnel", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Unknown", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "UnpavedRoad", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Wall", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Water", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Wire", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
}

///////////////////////////////////////////////////////////////////////
// Argument Parsing Functions
////////////////////////////////////////////////////////////////////////

static int
ParseArgs(int argc, char **argv)
{
  // Parse arguments
  argc--; argv++;
  while (argc > 0) {
    if ((*argv)[0] == '-') {
      if (!strcmp(*argv, "-v")) {
        print_verbose = 1;
      }
      else if (!strcmp(*argv, "-multiresolution")) {
        multiresolution = 1;
      }
      else if (!strcmp(*argv, "-dynamic_cache")) {
        dynamic_cache = 1;
      }
      else if (!strcmp(*argv, "-pixel_database")) {
        argv++; argc--; input_pixel_database_filename = *argv;
      }
      else if (!strcmp(*argv, "-image_directory")) {
        argv++; argc--; input_image_directory = *argv;
      }
      else if (!strcmp(*argv, "-history")) {
        argc--; argv++; output_history_filename = *argv;
      }
      else if (!strcmp(*argv, "-snapshot_directory")) {
        argc--; argv++; output_snapshot_directory = *argv;
      }
      else if (!strcmp(*argv, "-depth_scale")) {
        argv++; argc--; depth_scale = atof(*argv);
      }
      else if (!strcmp(*argv, "-depth_exponent")) {
        argv++; argc--; depth_exponent = atof(*argv);
      }
      else if (!strcmp(*argv, "-max_images")) {
        argv++; argc--; max_images = atoi(*argv);
      }
      else if (!strcmp(*argv, "-apply_may2022_scene_updates")) {
        apply_may2022_scene_updates = 1;
      }
      else {
        RNFail("Invalid program argument: %s", *argv);
        exit(1);
      }
      argv++; argc--;
    }
    else {
      if (!scene_filename) scene_filename = *argv;
      else if (!database_filename) database_filename = *argv;
      else { RNFail("Invalid program argument: %s", *argv); exit(1); }
      argv++; argc--;
    }
  }

  // Check surfels name
  if (!scene_filename || !database_filename) {
    RNFail("Usage: sfllabel scenefile databasefile [options]\n");
    return FALSE;
  }

  // Return OK status
  return 1;
}

////////////////////////////////////////////////////////////////////////
// Main
////////////////////////////////////////////////////////////////////////

int main(int argc, char **argv)
{
  // Initialize packages
  if (!R3InitGraphics()) exit(-1);
  if (!R3InitSurfels()) exit(-1);

  // Parse program arguments
  if (!ParseArgs(argc, argv)) exit(-1);

  // Open scene
  R3SurfelScene *scene = OpenScene(scene_filename, database_filename, print_verbose);
  if (!scene) exit(-1);

  // TEMPORARY
  if (apply_may2022_scene_updates) {
    ApplyMay2022SceneUpdates(scene);
  }

  // Read images
  if (input_pixel_database_filename) {
    if (!ReadImagesFromPixelDatabase(scene, input_pixel_database_filename,
      depth_scale, depth_exponent, max_images, print_verbose)) exit(-1);
  }
  else if (input_image_directory) {
    if (!ReadImagesFromDirectory(scene, input_image_directory,
      depth_scale, depth_exponent, max_images, print_verbose)) exit(-1);
  }

  // Create labeler
  R3SurfelLabeler *labeler = new R3SurfelLabeler(scene, output_history_filename);
  if (!labeler) exit(-1);

  // Check if should read everything into memory always
  if (!dynamic_cache) {
    labeler->ReadCoarsestBlocks(FLT_MAX);
  }

  // Check if should draw everything at full res always
  if (!multiresolution) {
    labeler->SetFocusRadius(RN_INFINITY);
    labeler->SetTargetResolution(RN_INFINITY);
  }

  // Check if should output snapshots
  if (output_snapshot_directory) {
    labeler->SetSnapshotDirectory(output_snapshot_directory);
    labeler->Snapshot();
  }

  // Run interface
  UIInterface(labeler);

  // Terminate labeler
  if (labeler) labeler->Terminate();

  // Close scene
  if (scene) CloseScene(scene, print_verbose);

  // Return success
  return 0;
}

<commit_msg>may2022<commit_after>// Source file for the surfel labeler program

////////////////////////////////////////////////////////////////////////
// Include files
////////////////////////////////////////////////////////////////////////

namespace gaps {}
using namespace gaps;
#include "R3Utils/R3Utils.h"
#include "io.h"
#include "ui.h"

////////////////////////////////////////////////////////////////////////
// Program arguments
////////////////////////////////////////////////////////////////////////

static const char *scene_filename = NULL;
static const char *database_filename = NULL;
static const char *input_pixel_database_filename = NULL;
static const char *input_image_directory = NULL;
static const char *output_history_filename = NULL;
static const char *output_snapshot_directory = NULL;
static double depth_scale = 2000;
static double depth_exponent = 0.5;
static int multiresolution = 0;
static int dynamic_cache = 0;
static int max_images = 0;
static int apply_may2022_scene_updates = 0;
static int print_verbose = 0;

///////////////////////////////////////////////////////////////////////
// Apply temporary scene modifications
////////////////////////////////////////////////////////////////////////

static int
AddLabel(R3SurfelScene *scene, const char *name,
  int identifier, int assignment_key,
  int r, int g, int b, const char *parent_name = NULL)
{
  // Check stuff
  if (!scene) return 0;
  if (!name) return 0;

  // Check if label already exists
  if (scene->FindLabelByName(name)) return 1;

  // Find parent label
  R3SurfelLabel *parent = scene->RootLabel();
  if (parent_name) parent = scene->FindLabelByName(parent_name);
  if (!parent) return 0;

  // Create label
  R3SurfelLabel *label =  new R3SurfelLabel(name);
  label->SetColor(gaps::RNRgb(r / 255.0, g / 255.0, b / 255.0));
  label->SetIdentifier(identifier);
  label->SetAssignmentKeystroke(assignment_key);
  scene->InsertLabel(label, parent);

  // Return success
  return 1;
}

static int
AddLabelFlags(R3SurfelScene *scene, const char *label_name, RNFlags flags)
{
  // Find label
  R3SurfelLabel *label = scene->FindLabelByName(label_name);
  if (!label) return 0;

  // Update label flags
  RNFlags label_flags = label->Flags();
  label_flags.Add(flags);
  label->SetFlags(label_flags);

  // Return success
  return 1;
}

static int
SetLabelAssignmentKey(R3SurfelScene *scene, const char *label_name, int assignment_key)
{
  // Find label
  R3SurfelLabel *label = scene->FindLabelByName(label_name);
  if (!label) return 0;

  // Update assignment key
  label->SetAssignmentKeystroke(assignment_key);

  // Return success
  return 1;
}

static void
ApplyMay2022SceneUpdates(R3SurfelScene *scene)
{
  // Reset label assignment keys
  SetLabelAssignmentKey(scene, "OtherVehicle", 'C');

  // Add new labels
  const int PEDESTRIAN_ENTRANCE_LABEL = 47;
  const int VEHICLE_ENTRANCE_LABEL = 48;
  AddLabel(scene, "PedestrianEntrance", PEDESTRIAN_ENTRANCE_LABEL, 'n', 240, 140, 140);
  AddLabel(scene, "VehicleEntrance", VEHICLE_ENTRANCE_LABEL, 'v', 240, 0, 240);

  // Add label axis flags
  AddLabelFlags(scene, "Billboard", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "BusinessSign", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "PedestrianEntrance", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "TempTrafficSign", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "TrafficSign", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);
  AddLabelFlags(scene, "VehicleEntrance", R3_SURFEL_LABEL_SHORT_AXIS_TOWARDS_FRONT_FLAG);

  // Add label unorientable flags
  AddLabelFlags(scene, "Bridge", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "BuildingInterior", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "BuildingExterior", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "BusStop", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Crosswalk", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Driveway", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Fence", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "FireHydrant", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "GuardRail", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "LidarArtifact", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Mountain", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherGround", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherPermObject", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherStructure", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "OtherTempObject", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "ParkingMeter", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "PavedRoad", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Pole", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Self", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Sidewalk", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Sky", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "StreetLight", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "TempCone", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Terrain", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Tree", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Tunnel", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Unknown", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "UnpavedRoad", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Wall", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Water", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
  AddLabelFlags(scene, "Wire", R3_SURFEL_LABEL_UNORIENTABLE_FLAG);
}

///////////////////////////////////////////////////////////////////////
// Argument Parsing Functions
////////////////////////////////////////////////////////////////////////

static int
ParseArgs(int argc, char **argv)
{
  // Parse arguments
  argc--; argv++;
  while (argc > 0) {
    if ((*argv)[0] == '-') {
      if (!strcmp(*argv, "-v")) {
        print_verbose = 1;
      }
      else if (!strcmp(*argv, "-multiresolution")) {
        multiresolution = 1;
      }
      else if (!strcmp(*argv, "-dynamic_cache")) {
        dynamic_cache = 1;
      }
      else if (!strcmp(*argv, "-pixel_database")) {
        argv++; argc--; input_pixel_database_filename = *argv;
      }
      else if (!strcmp(*argv, "-image_directory")) {
        argv++; argc--; input_image_directory = *argv;
      }
      else if (!strcmp(*argv, "-history")) {
        argc--; argv++; output_history_filename = *argv;
      }
      else if (!strcmp(*argv, "-snapshot_directory")) {
        argc--; argv++; output_snapshot_directory = *argv;
      }
      else if (!strcmp(*argv, "-depth_scale")) {
        argv++; argc--; depth_scale = atof(*argv);
      }
      else if (!strcmp(*argv, "-depth_exponent")) {
        argv++; argc--; depth_exponent = atof(*argv);
      }
      else if (!strcmp(*argv, "-max_images")) {
        argv++; argc--; max_images = atoi(*argv);
      }
      else if (!strcmp(*argv, "-apply_may2022_scene_updates")) {
        apply_may2022_scene_updates = 1;
      }
      else {
        RNFail("Invalid program argument: %s", *argv);
        exit(1);
      }
      argv++; argc--;
    }
    else {
      if (!scene_filename) scene_filename = *argv;
      else if (!database_filename) database_filename = *argv;
      else { RNFail("Invalid program argument: %s", *argv); exit(1); }
      argv++; argc--;
    }
  }

  // Check surfels name
  if (!scene_filename || !database_filename) {
    RNFail("Usage: sfllabel scenefile databasefile [options]\n");
    return FALSE;
  }

  // Return OK status
  return 1;
}

////////////////////////////////////////////////////////////////////////
// Main
////////////////////////////////////////////////////////////////////////

int main(int argc, char **argv)
{
  // Initialize packages
  if (!R3InitGraphics()) exit(-1);
  if (!R3InitSurfels()) exit(-1);

  // Parse program arguments
  if (!ParseArgs(argc, argv)) exit(-1);

  // Open scene
  R3SurfelScene *scene = OpenScene(scene_filename, database_filename, print_verbose);
  if (!scene) exit(-1);

  // TEMPORARY
  if (apply_may2022_scene_updates) {
    ApplyMay2022SceneUpdates(scene);
  }

  // Read images
  if (input_pixel_database_filename) {
    if (!ReadImagesFromPixelDatabase(scene, input_pixel_database_filename,
      depth_scale, depth_exponent, max_images, print_verbose)) exit(-1);
  }
  else if (input_image_directory) {
    if (!ReadImagesFromDirectory(scene, input_image_directory,
      depth_scale, depth_exponent, max_images, print_verbose)) exit(-1);
  }

  // Create labeler
  R3SurfelLabeler *labeler = new R3SurfelLabeler(scene, output_history_filename);
  if (!labeler) exit(-1);

  // Check if should read everything into memory always
  if (!dynamic_cache) {
    labeler->ReadCoarsestBlocks(FLT_MAX);
  }

  // Check if should draw everything at full res always
  if (!multiresolution) {
    labeler->SetFocusRadius(RN_INFINITY);
    labeler->SetTargetResolution(RN_INFINITY);
  }

  // Check if should output snapshots
  if (output_snapshot_directory) {
    labeler->SetSnapshotDirectory(output_snapshot_directory);
    labeler->Snapshot();
  }

  // Run interface
  UIInterface(labeler);

  // Terminate labeler
  if (labeler) labeler->Terminate();

  // Close scene
  if (scene) CloseScene(scene, print_verbose);

  // Return success
  return 0;
}

<|endoftext|>


<commit_before>#ifndef BFC_COMBINE_INC_VISITOR_HPP
#define BFC_COMBINE_INC_VISITOR_HPP

namespace bfc {
namespace ast {

class combine_inc_visitor : public opt_seq_base_visitor {

public:

    status visit(add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(const add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

    status visit(const sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

private:

    class try_combine_inc_visitor : public test_visitor {

        public:
            try_combine_inc_visitor(ptrdiff_t offset, bf_value val, bool isAdd) :
                next_off(offset), next_val(val), isAdd(isAdd) {}

            bf_value new_value() {
                return new_val;
            }

            status visit(add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
            }

            status visit(const add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
            }
            status visit(sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val -= next_val : new_val += next_val;
                node.value(new_val);
            }
            status visit(const sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val -= next_val : new_val += next_val;
                node.value(new_val);
            }

        private:
            bool isAdd;
            ptrdiff_t next_off;
            bf_value next_val;
            bf_value new_val;

    };

};

}
}

#endif /* !BFC_COMBINE_INC_VISITOR_HPP */
<commit_msg>Combine increments with previous set instructions<commit_after>#ifndef BFC_COMBINE_INC_VISITOR_HPP
#define BFC_COMBINE_INC_VISITOR_HPP

namespace bfc {
namespace ast {

class combine_inc_visitor : public opt_seq_base_visitor {

public:

    status visit(add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(const add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

    status visit(const sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            node prev_node = opt_seq.back();
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (prev_node.accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

private:

    class try_combine_inc_visitor : public test_visitor {

        public:
            try_combine_inc_visitor(ptrdiff_t offset, bf_value val, bool isAdd) :
                next_off(offset), next_val(val), isAdd(isAdd) {}

            bf_value new_value() {
                return new_val;
            }

            status visit(set &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
            }

            status visit(const set &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
            }

            status visit(add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
            }

            status visit(const add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
            }
            status visit(sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val -= next_val : new_val += next_val;
                node.value(new_val);
            }
            status visit(const sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value()
                isAdd ? new_val -= next_val : new_val += next_val;
                node.value(new_val);
            }

        private:
            bool isAdd;
            ptrdiff_t next_off;
            bf_value next_val;
            bf_value new_val;

    };

};

}
}

#endif /* !BFC_COMBINE_INC_VISITOR_HPP */
<|endoftext|>


<commit_before>/*!
    \file format.inl
    \brief Format string inline implementation
    \author Ivan Shynkarenka
    \date 16.09.2016
    \copyright MIT License
*/

namespace CppCommon {

template <typename... Args>
std::string format(const std::string& pattern, const Args&... args)
{
    return fmt::format(pattern, args...);
}

template <typename... Args>
std::wstring format(const std::wstring& pattern, const Args&... args)
{
    return fmt::format(pattern, args...);
}

} // namespace CppCommon

//! @cond INTERNALS

inline fmt::internal::udl_arg<char> operator"" _a(const char* str, std::size_t) { return { str }; }
inline fmt::internal::udl_arg<wchar_t> operator"" _a(const wchar_t* str, std::size_t) { return { str }; }
inline fmt::internal::udl_formatter<char> operator"" _format(const char* str, std::size_t) { return { str }; }
inline fmt::internal::udl_formatter<wchar_t> operator"" _format(const wchar_t* str, std::size_t) { return { str }; }

//! @endcond
<commit_msg>update<commit_after>/*!
    \file format.inl
    \brief Format string inline implementation
    \author Ivan Shynkarenka
    \date 16.09.2016
    \copyright MIT License
*/

namespace CppCommon {

template <typename... Args>
std::string format(const std::string& pattern, const Args&... args)
{
    return fmt::format(pattern, args...);
}

template <typename... Args>
std::wstring format(const std::wstring& pattern, const Args&... args)
{
    return fmt::format(pattern, args...);
}

} // namespace CppCommon

//! @cond INTERNALS

inline fmt::internal::udl_arg<char> operator""_a(const char* str, std::size_t) { return { str }; }
inline fmt::internal::udl_arg<wchar_t> operator""_a(const wchar_t* str, std::size_t) { return { str }; }
#if defined(_MSC_VER)
inline fmt::internal::udl_formatter<char> operator""_format(const char* str, std::size_t) { return { str }; }
inline fmt::internal::udl_formatter<wchar_t> operator""_format(const wchar_t* str, std::size_t) { return { str }; }
#else
template <typename TChar, TChar... CHARS>
FMT_CONSTEXPR fmt::internal::udl_formatter<TChar, CHARS...> operator""_format() { return {}; }
#endif

//! @endcond
<|endoftext|>


<commit_before><commit_msg>Do not needlessly truncate MinMax argument before comparison with bounds<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: mergekeys.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 07:55:25 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <vector>

#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/registry/MergeConflictException.hpp>

#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

using namespace ::rtl;
using namespace ::osl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;

namespace stoc_impreg
{

struct Link
{
    OUString m_name;
    OUString m_target;

    inline Link( OUString const & name, OUString const & target ) SAL_THROW( () )
        : m_name( name )
        , m_target( target )
        {}
};
typedef ::std::vector< Link > t_links;

//==================================================================================================
static void mergeKeys(
    Reference< registry::XRegistryKey > const & xDest,
    Reference< registry::XRegistryKey > const & xSource,
    t_links & links )
    SAL_THROW( (registry::InvalidRegistryException, registry::MergeConflictException) )
{
    if (!xSource.is() || !xSource->isValid()) {
        throw registry::InvalidRegistryException(
            OUSTR("source key is null or invalid!"),
            Reference<XInterface>() );
    }
    if (!xDest.is() || !xDest->isValid()) {
        throw registry::InvalidRegistryException(
            OUSTR("destination key is null or invalid!"),
            Reference<XInterface>() );
    }

    // write value
    switch (xSource->getValueType())
    {
    case registry::RegistryValueType_NOT_DEFINED:
        break;
    case registry::RegistryValueType_LONG:
        xDest->setLongValue( xSource->getLongValue() );
        break;
    case registry::RegistryValueType_ASCII:
        xDest->setAsciiValue( xSource->getAsciiValue() );
        break;
    case registry::RegistryValueType_STRING:
        xDest->setStringValue( xSource->getStringValue() );
        break;
    case registry::RegistryValueType_BINARY:
        xDest->setBinaryValue( xSource->getBinaryValue() );
        break;
    case registry::RegistryValueType_LONGLIST:
        xDest->setLongListValue( xSource->getLongListValue() );
        break;
    case registry::RegistryValueType_ASCIILIST:
        xDest->setAsciiListValue( xSource->getAsciiListValue() );
        break;
    case registry::RegistryValueType_STRINGLIST:
        xDest->setStringListValue( xSource->getStringListValue() );
        break;
    }

    // sub keys
    Sequence< OUString > sourceKeys( xSource->getKeyNames() );
    OUString const * pSourceKeys = sourceKeys.getConstArray();
    for ( sal_Int32 nPos = sourceKeys.getLength(); nPos--; )
    {
        // key name
        OUString name( pSourceKeys[ nPos ] );
        sal_Int32 nSlash = name.lastIndexOf( '/' );
        if (nSlash >= 0)
        {
            name = name.copy( nSlash +1 );
        }

        if (xSource->getKeyType( name ) == registry::RegistryKeyType_KEY)
        {
            // try to open exisiting dest key or create new one
            Reference< registry::XRegistryKey > xDestKey( xDest->createKey( name ) );
            Reference< registry::XRegistryKey > xSourceKey( xSource->openKey( name ) );
            mergeKeys( xDestKey, xSourceKey, links );
            xSourceKey->closeKey();
            xDestKey->closeKey();
        }
        else // link
        {
            // remove existing key
            Reference< registry::XRegistryKey > xDestKey( xDest->openKey( name ) );
            if (xDestKey.is() && xDestKey->isValid()) // something to remove
            {
                xDestKey->closeKey();
                if (xDest->getKeyType( name ) == registry::RegistryKeyType_LINK)
                {
                    xDest->deleteLink( name );
                }
                else
                {
                    xDest->deleteKey( name );
                }
            }

            links.push_back( Link(
                pSourceKeys[ nPos ], // abs path
                xSource->getResolvedName( name ) // abs resolved name
                ) );
        }
    }
}

//==================================================================================================
void SAL_CALL mergeKeys(
    Reference< registry::XRegistryKey > const & xDest,
    Reference< registry::XRegistryKey > const & xSource )
    SAL_THROW( (registry::InvalidRegistryException, registry::MergeConflictException) )
{
    if (!xDest.is() || !xDest->isValid()) {
        throw registry::InvalidRegistryException(
            OUSTR("destination key is null or invalid!"),
            Reference<XInterface>() );
    }
    if (xDest->isReadOnly())
    {
        throw registry::InvalidRegistryException(
            OUString( RTL_CONSTASCII_USTRINGPARAM(
                          "destination registry is read-only!  cannot merge!") ),
            Reference< XInterface >() );
    }

    t_links links;
    links.reserve( 16 );
    mergeKeys( xDest, xSource, links );

    for ( size_t nPos = links.size(); nPos--; )
    {
        Link const & r = links[ nPos ];
        OSL_VERIFY( xDest->createLink( r.m_name, r.m_target ) );
    }
}

}
<commit_msg>INTEGRATION: CWS warnings01 (1.3.22); FILE MERGED 2005/09/22 19:47:51 sb 1.3.22.2: RESYNC: (1.3-1.4); FILE MERGED 2005/09/01 15:24:38 sb 1.3.22.1: #i53898# Made code warning-free.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: mergekeys.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 00:02:03 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <vector>

#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/registry/MergeConflictException.hpp>

#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )

using namespace ::rtl;
using namespace ::osl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;

namespace stoc_impreg
{

struct Link
{
    OUString m_name;
    OUString m_target;

    inline Link( OUString const & name, OUString const & target ) SAL_THROW( () )
        : m_name( name )
        , m_target( target )
        {}
};
typedef ::std::vector< Link > t_links;

//==================================================================================================
static void mergeKeys(
    Reference< registry::XRegistryKey > const & xDest,
    Reference< registry::XRegistryKey > const & xSource,
    t_links & links )
    SAL_THROW( (registry::InvalidRegistryException, registry::MergeConflictException) )
{
    if (!xSource.is() || !xSource->isValid()) {
        throw registry::InvalidRegistryException(
            OUSTR("source key is null or invalid!"),
            Reference<XInterface>() );
    }
    if (!xDest.is() || !xDest->isValid()) {
        throw registry::InvalidRegistryException(
            OUSTR("destination key is null or invalid!"),
            Reference<XInterface>() );
    }

    // write value
    switch (xSource->getValueType())
    {
    case registry::RegistryValueType_NOT_DEFINED:
        break;
    case registry::RegistryValueType_LONG:
        xDest->setLongValue( xSource->getLongValue() );
        break;
    case registry::RegistryValueType_ASCII:
        xDest->setAsciiValue( xSource->getAsciiValue() );
        break;
    case registry::RegistryValueType_STRING:
        xDest->setStringValue( xSource->getStringValue() );
        break;
    case registry::RegistryValueType_BINARY:
        xDest->setBinaryValue( xSource->getBinaryValue() );
        break;
    case registry::RegistryValueType_LONGLIST:
        xDest->setLongListValue( xSource->getLongListValue() );
        break;
    case registry::RegistryValueType_ASCIILIST:
        xDest->setAsciiListValue( xSource->getAsciiListValue() );
        break;
    case registry::RegistryValueType_STRINGLIST:
        xDest->setStringListValue( xSource->getStringListValue() );
        break;
    default:
        OSL_ASSERT(false);
        break;
    }

    // sub keys
    Sequence< OUString > sourceKeys( xSource->getKeyNames() );
    OUString const * pSourceKeys = sourceKeys.getConstArray();
    for ( sal_Int32 nPos = sourceKeys.getLength(); nPos--; )
    {
        // key name
        OUString name( pSourceKeys[ nPos ] );
        sal_Int32 nSlash = name.lastIndexOf( '/' );
        if (nSlash >= 0)
        {
            name = name.copy( nSlash +1 );
        }

        if (xSource->getKeyType( name ) == registry::RegistryKeyType_KEY)
        {
            // try to open exisiting dest key or create new one
            Reference< registry::XRegistryKey > xDestKey( xDest->createKey( name ) );
            Reference< registry::XRegistryKey > xSourceKey( xSource->openKey( name ) );
            mergeKeys( xDestKey, xSourceKey, links );
            xSourceKey->closeKey();
            xDestKey->closeKey();
        }
        else // link
        {
            // remove existing key
            Reference< registry::XRegistryKey > xDestKey( xDest->openKey( name ) );
            if (xDestKey.is() && xDestKey->isValid()) // something to remove
            {
                xDestKey->closeKey();
                if (xDest->getKeyType( name ) == registry::RegistryKeyType_LINK)
                {
                    xDest->deleteLink( name );
                }
                else
                {
                    xDest->deleteKey( name );
                }
            }

            links.push_back( Link(
                pSourceKeys[ nPos ], // abs path
                xSource->getResolvedName( name ) // abs resolved name
                ) );
        }
    }
}

//==================================================================================================
void SAL_CALL mergeKeys(
    Reference< registry::XRegistryKey > const & xDest,
    Reference< registry::XRegistryKey > const & xSource )
    SAL_THROW( (registry::InvalidRegistryException, registry::MergeConflictException) )
{
    if (!xDest.is() || !xDest->isValid()) {
        throw registry::InvalidRegistryException(
            OUSTR("destination key is null or invalid!"),
            Reference<XInterface>() );
    }
    if (xDest->isReadOnly())
    {
        throw registry::InvalidRegistryException(
            OUString( RTL_CONSTASCII_USTRINGPARAM(
                          "destination registry is read-only!  cannot merge!") ),
            Reference< XInterface >() );
    }

    t_links links;
    links.reserve( 16 );
    mergeKeys( xDest, xSource, links );

    for ( size_t nPos = links.size(); nPos--; )
    {
        Link const & r = links[ nPos ];
        OSL_VERIFY( xDest->createLink( r.m_name, r.m_target ) );
    }
}

}
<|endoftext|>