<commit_before>#ifndef LIBTEN_METRICS_HH
#define LIBTEN_METRICS_HH

#include "ten/thread_local.hh"
#include "ten/synchronized.hh"
#include "ten/logging.hh"
#include "ten/json.hh"
#include <boost/utility.hpp>
#include <boost/variant.hpp>
#include <chrono>
#include <unordered_map>
#include <memory>
#include <algorithm>
#include <sstream>

namespace ten {
namespace metrics {

// convenience wrappers to create metric names.
//   join('.', @arg)  # equivalent Perl

namespace impl {
template <typename Arg>
inline void path_shift(std::stringstream &ss, Arg arg) {
    ss << std::forward<Arg>(arg);
}

template <typename Arg, typename ...Args>
inline void path_shift(std::stringstream &ss, Arg arg, Args... args) {
    ss << arg << ".";
    path_shift(ss, std::forward<Args>(args)...);
}
} // namespace impl

inline std::string metric_path(const std::string &arg) { return arg; }
inline std::string metric_path(std::string &&arg)      { return arg; }

template <typename Arg, typename ...Args>
inline std::string metric_path(Arg arg, Args... args) {
    std::stringstream ss;
    impl::path_shift(ss, std::forward<Arg>(arg), std::forward<Args>(args)...);
    return ss.str();
}

// metric classes with common base

class metric {
public:
    virtual ~metric() {}
    virtual json to_json() const = 0;
};

class counter : public metric {
public:
    using value_type = int64_t;

private:
    value_type _count = 0;

public:
    ~counter() override {};

    json to_json() const override {
        return ten::to_json(value());
    }

    value_type value() const {
        return _count;
    }

    void incr(value_type n = 1) {
        _count+=n;
    }

    void merge(const counter &other) {
        _count += other._count;
    }
};

// TODO: allow for ratio in json
// with incr/decr. provide names for numerator/denominator
class gauge : public metric {
public:
    using value_type = int64_t;

private:
    value_type _incr = 0;
    value_type _decr = 0;

public:
    ~gauge() override {};

    json to_json() const override {
        return ten::json::array({value(), _incr, _decr});
    }

    void merge(const gauge &other) {
        _incr += other._incr;
        _decr += other._decr;
    }

    void incr(value_type n=1) {
        _incr+=n;
    }

    void decr(value_type n=1) {
        _decr+=n;
    }

    value_type value() const {
        return _incr - _decr;
    }

    std::pair<value_type, value_type> value_pair() const {
        return std::make_pair(_incr, _decr);
    }

    double ratio() const {
        return _decr/_incr;
    }
};

// report in JSON as floating point milliseconds; keep as tenths of milliseconds
class timer : public metric {
public:
    using value_type = std::chrono::microseconds;
    using clock_type = std::chrono::high_resolution_clock;

private:
    clock_type::duration _elapsed;

public:
    ~timer() override {};

    json to_json() const override {
        // value units: microseconds
        // display units: milliseconds
        // resolution: centiseconds
        auto cents = value().count() / 100;
        return ten::to_json((double)cents / 10.0);
    }

    // caller specifies desired duration type to avoid misinterpreting .count()
    value_type value() const {
        return std::chrono::duration_cast<value_type>(_elapsed);
    }

    void update(clock_type::duration elapsed) {
        _elapsed += elapsed;
    }

    void merge(const timer &other) {
        _elapsed += other._elapsed;
    }
};

// variant of all possible metrics
typedef boost::variant<counter, gauge, timer> any_metric;

struct merge_visitor : boost::static_visitor<> {
    any_metric &_lhs;

    merge_visitor(any_metric &lhs) : _lhs(lhs){}

    template <typename M>
        void operator()(const M &rhs) const {
            boost::get<M>(_lhs).merge(rhs);
        }
};

// collection of arbitrary metrics with arbitrary names

typedef std::unordered_map<std::string, any_metric> metric_map;

template <typename M>
    inline M &get(metric_map &mm, const std::string &name) {
        auto i = mm.find(name);
        if (i == end(mm)) {
            auto ii = mm.emplace(name, M());
            i = ii.first;
        }
        return boost::get<M>(i->second);
    }

template <typename M>
    inline typename M::value_type value(const metric_map &mm, const std::string &name) {
        auto i = mm.find(name);
        return (i == end(mm))
            ? typename M::value_type()
            : boost::get<M>(i->second).value();
    }

// a lockable wrapper around metric_map
// TODO: replace with synchronized<metric_map>

class metric_group {
    metric_map _map;
    mutable std::mutex _mtx;

public:
    struct mg_lock : std::unique_lock<std::mutex> {
        mg_lock(const metric_group &g) : unique_lock(g._mtx) {}
    };

    metric_group();
    ~metric_group();

    metric_group(const metric_group &) = delete;
    metric_group & operator = (const metric_group &) = delete;

    metric_group(metric_group &&) = default;
    metric_group & operator = (metric_group &&) = default;

    // unsafe accessors; typically should be used via chain

    template <typename M>
        M &get(const std::string &name)
            { return metrics::get<M>(_map, name); }

    template <typename M>
        typename M::value_type value(const std::string &name) const
            { return metrics::value<M>(_map, name); }

    // safe mass merge

    void safe_merge_to(metric_map &ag) const {
        mg_lock(*this);
        for (const auto &kv : _map) {
            // try to insert into merged map
            const auto i = ag.insert(kv);
            if (!i.second) {
                // merge with existing
                boost::apply_visitor(merge_visitor(i.first->second), kv.second);
            }
        }
    }
};

// a chain is a move-semantic locked accessor for a metric_group

class chain {
    metric_group * const _mg;
    metric_group::mg_lock _lock;

public:
    chain(metric_group *mg) : _mg(mg), _lock(*mg) {}

    chain(const chain &) = delete;
    chain & operator = (const chain &) = delete;

    chain(chain &&) = default;
    chain & operator = (chain &&) = default;

    template <typename ...Args>
        metrics::counter &counter(Args ...args) {
            return _mg->get<metrics::counter>(metric_path(std::forward<Args>(args)...));
        }

    template <typename ...Args>
        metrics::gauge &gauge(Args ...args) {
            return _mg->get<metrics::gauge>(metric_path(std::forward<Args>(args)...));
        }

    template <typename ...Args>
        metrics::timer &timer(Args ...args) {
            return _mg->get<metrics::timer>(metric_path(std::forward<Args>(args)...));
        }

};

struct metric_tag {};
extern thread_cached<metric_tag, metric_group> tls_metric_group;

inline chain record() {
    return chain(tls_metric_group.get());
}

template <typename Func>
inline void record(Func &&f) {
    metric_group *mg = tls_metric_group.get();
    metric_group::mg_lock lk(*mg);
    f(std::ref(*mg));
}

struct json_visitor : boost::static_visitor<json> {
    template <typename Met>
        json operator()(const Met &m) const {
            return m.to_json();
        }
};

// singleton global metrics, accumulated from individual activities

class metric_global;
extern metric_global global;

class metric_global {
public:
    struct data {
        std::vector<metric_group *> groups;
        metric_map removed;
    };
    synchronized<data> _data;

    metric_global() {}
    ~metric_global() {}

    void push_back(metric_group *g) {
        synchronize(_data, [&](data &d) {
            d.groups.push_back(g);
        });
    }

    // TODO: dont actually want to remove the group until the stats have been merged
    // otherwise a thread could spawn and exit before an aggregation and the metrics
    // would be lost.  this suggests that groups should be on the heap
    void remove(metric_group *g) {
        synchronize(_data, [&](data &d) {
            const auto i = std::find(std::begin(d.groups), std::end(d.groups), g);
            CHECK(i != std::end(d.groups));
            (*i)->safe_merge_to(d.removed); // keep stats for removed threads around
            d.groups.erase(i);
        });
    }

    metric_map aggregate() {
        metric_map ag;
        synchronize(_data, [&](data &d) {
            ag = d.removed; // copy all the removed stats into aggregate
            for (auto g : d.groups) {
                g->safe_merge_to(ag);
            }
        });
        return ag;
    }
};

inline metric_group::metric_group()   { global.push_back(this); }
inline metric_group::~metric_group()  { global.remove(this); }

// scoped timer convenience

template <class MG>
class time_op_base {
protected:
    using clock_type = timer::clock_type;

    MG &_mg;
    std::string _name;
    clock_type::time_point _start;
    bool _stopped = false;

    template <typename ...Args>
        time_op_base(MG &mg, Args ...args)
            : _mg(mg),
              _name(metric_path(std::forward<Args>(args)...)),
              _start(clock_type::now()) {}

    time_op_base(const time_op_base &) = delete;
    time_op_base & operator = (const time_op_base &) = delete;

    time_op_base(time_op_base &&) = default;
    time_op_base & operator = (time_op_base &&) = default;
};

class time_op : public time_op_base<metric_group> {
public:
    template <typename ...Args>
        time_op(metric_group &mg, Args ...args)
            : time_op_base(mg, std::forward<Args>(args)...) {}

    template <typename ...Args>
        time_op(Args ...args)
            : time_op_base(*tls_metric_group.get(), std::forward<Args>(args)...) {}

    ~time_op() {
        stop();
    }
    void stop() {
        // can't stop more than once
        if (_stopped) return;
        _stopped = true;
        const auto dur = clock_type::now() - _start;
        metric_group::mg_lock lk(_mg);
        _mg.get<timer>(_name).update(dur);
    }
};

// use only when you are safe from multithreading
class map_time_op : public time_op_base<metric_map> {
public:
    template <typename ...Args>
        map_time_op(metric_map &mm, Args ...args)
            : time_op_base(mm, std::forward<Args>(args)...) {}

    ~map_time_op() {
        stop();
    }
    void stop() {
        // can't stop more than once
        if (_stopped) return;
        _stopped = true;
        const auto dur = clock_type::now() - _start;
        get<timer>(_mg, _name).update(dur);
    }
};

} // end namespace metrics
} // end namespace ten

#endif
<commit_msg>use rvalue references for forwarding<commit_after>#ifndef LIBTEN_METRICS_HH
#define LIBTEN_METRICS_HH

#include "ten/thread_local.hh"
#include "ten/synchronized.hh"
#include "ten/logging.hh"
#include "ten/json.hh"
#include <boost/utility.hpp>
#include <boost/variant.hpp>
#include <chrono>
#include <unordered_map>
#include <memory>
#include <algorithm>
#include <sstream>

namespace ten {
namespace metrics {

// convenience wrappers to create metric names.
//   join('.', @arg)  # equivalent Perl

namespace impl {
template <typename Arg>
inline void path_shift(std::stringstream &ss, Arg&& arg) {
    ss << std::forward<Arg>(arg);
}

template <typename Arg, typename ...Args>
inline void path_shift(std::stringstream &ss, Arg&& arg, Args&& ...args) {
    ss << arg << ".";
    path_shift(ss, std::forward<Args>(args)...);
}
} // namespace impl

inline std::string metric_path(const std::string &arg) { return arg; }
inline std::string metric_path(std::string &&arg)      { return arg; }

template <typename Arg, typename ...Args>
inline std::string metric_path(Arg&& arg, Args&& ...args) {
    std::stringstream ss;
    impl::path_shift(ss, std::forward<Arg>(arg), std::forward<Args>(args)...);
    return ss.str();
}

// metric classes with common base

class metric {
public:
    virtual ~metric() {}
    virtual json to_json() const = 0;
};

class counter : public metric {
public:
    using value_type = int64_t;

private:
    value_type _count = 0;

public:
    ~counter() override {};

    json to_json() const override {
        return ten::to_json(value());
    }

    value_type value() const {
        return _count;
    }

    void incr(value_type n = 1) {
        _count+=n;
    }

    void merge(const counter &other) {
        _count += other._count;
    }
};

// TODO: allow for ratio in json
// with incr/decr. provide names for numerator/denominator
class gauge : public metric {
public:
    using value_type = int64_t;

private:
    value_type _incr = 0;
    value_type _decr = 0;

public:
    ~gauge() override {};

    json to_json() const override {
        return ten::json::array({value(), _incr, _decr});
    }

    void merge(const gauge &other) {
        _incr += other._incr;
        _decr += other._decr;
    }

    void incr(value_type n=1) {
        _incr+=n;
    }

    void decr(value_type n=1) {
        _decr+=n;
    }

    value_type value() const {
        return _incr - _decr;
    }

    std::pair<value_type, value_type> value_pair() const {
        return std::make_pair(_incr, _decr);
    }

    double ratio() const {
        return _decr/_incr;
    }
};

// report in JSON as floating point milliseconds; keep as tenths of milliseconds
class timer : public metric {
public:
    using value_type = std::chrono::microseconds;
    using clock_type = std::chrono::high_resolution_clock;

private:
    clock_type::duration _elapsed;

public:
    ~timer() override {};

    json to_json() const override {
        // value units: microseconds
        // display units: milliseconds
        // resolution: centiseconds
        auto cents = value().count() / 100;
        return ten::to_json((double)cents / 10.0);
    }

    // caller specifies desired duration type to avoid misinterpreting .count()
    value_type value() const {
        return std::chrono::duration_cast<value_type>(_elapsed);
    }

    void update(clock_type::duration elapsed) {
        _elapsed += elapsed;
    }

    void merge(const timer &other) {
        _elapsed += other._elapsed;
    }
};

// variant of all possible metrics
typedef boost::variant<counter, gauge, timer> any_metric;

struct merge_visitor : boost::static_visitor<> {
    any_metric &_lhs;

    merge_visitor(any_metric &lhs) : _lhs(lhs){}

    template <typename M>
        void operator()(const M &rhs) const {
            boost::get<M>(_lhs).merge(rhs);
        }
};

// collection of arbitrary metrics with arbitrary names

typedef std::unordered_map<std::string, any_metric> metric_map;

template <typename M>
    inline M &get(metric_map &mm, const std::string &name) {
        auto i = mm.find(name);
        if (i == end(mm)) {
            auto ii = mm.emplace(name, M());
            i = ii.first;
        }
        return boost::get<M>(i->second);
    }

template <typename M>
    inline typename M::value_type value(const metric_map &mm, const std::string &name) {
        auto i = mm.find(name);
        return (i == end(mm))
            ? typename M::value_type()
            : boost::get<M>(i->second).value();
    }

// a lockable wrapper around metric_map
// TODO: replace with synchronized<metric_map>

class metric_group {
    metric_map _map;
    mutable std::mutex _mtx;

public:
    struct mg_lock : std::unique_lock<std::mutex> {
        mg_lock(const metric_group &g) : unique_lock(g._mtx) {}
    };

    metric_group();
    ~metric_group();

    metric_group(const metric_group &) = delete;
    metric_group & operator = (const metric_group &) = delete;

    metric_group(metric_group &&) = default;
    metric_group & operator = (metric_group &&) = default;

    // unsafe accessors; typically should be used via chain

    template <typename M>
        M &get(const std::string &name)
            { return metrics::get<M>(_map, name); }

    template <typename M>
        typename M::value_type value(const std::string &name) const
            { return metrics::value<M>(_map, name); }

    // safe mass merge

    void safe_merge_to(metric_map &ag) const {
        mg_lock(*this);
        for (const auto &kv : _map) {
            // try to insert into merged map
            const auto i = ag.insert(kv);
            if (!i.second) {
                // merge with existing
                boost::apply_visitor(merge_visitor(i.first->second), kv.second);
            }
        }
    }
};

// a chain is a move-semantic locked accessor for a metric_group

class chain {
    metric_group * const _mg;
    metric_group::mg_lock _lock;

public:
    chain(metric_group *mg) : _mg(mg), _lock(*mg) {}

    chain(const chain &) = delete;
    chain & operator = (const chain &) = delete;

    chain(chain &&) = default;
    chain & operator = (chain &&) = default;

    template <typename ...Args>
        metrics::counter &counter(Args&& ...args) {
            return _mg->get<metrics::counter>(metric_path(std::forward<Args>(args)...));
        }

    template <typename ...Args>
        metrics::gauge &gauge(Args&& ...args) {
            return _mg->get<metrics::gauge>(metric_path(std::forward<Args>(args)...));
        }

    template <typename ...Args>
        metrics::timer &timer(Args&& ...args) {
            return _mg->get<metrics::timer>(metric_path(std::forward<Args>(args)...));
        }

};

struct metric_tag {};
extern thread_cached<metric_tag, metric_group> tls_metric_group;

inline chain record() {
    return chain(tls_metric_group.get());
}

template <typename Func>
inline void record(Func &&f) {
    metric_group *mg = tls_metric_group.get();
    metric_group::mg_lock lk(*mg);
    f(std::ref(*mg));
}

struct json_visitor : boost::static_visitor<json> {
    template <typename Met>
        json operator()(const Met &m) const {
            return m.to_json();
        }
};

// singleton global metrics, accumulated from individual activities

class metric_global;
extern metric_global global;

class metric_global {
public:
    struct data {
        std::vector<metric_group *> groups;
        metric_map removed;
    };
    synchronized<data> _data;

    metric_global() {}
    ~metric_global() {}

    void push_back(metric_group *g) {
        synchronize(_data, [&](data &d) {
            d.groups.push_back(g);
        });
    }

    // TODO: dont actually want to remove the group until the stats have been merged
    // otherwise a thread could spawn and exit before an aggregation and the metrics
    // would be lost.  this suggests that groups should be on the heap
    void remove(metric_group *g) {
        synchronize(_data, [&](data &d) {
            const auto i = std::find(std::begin(d.groups), std::end(d.groups), g);
            CHECK(i != std::end(d.groups));
            (*i)->safe_merge_to(d.removed); // keep stats for removed threads around
            d.groups.erase(i);
        });
    }

    metric_map aggregate() {
        metric_map ag;
        synchronize(_data, [&](data &d) {
            ag = d.removed; // copy all the removed stats into aggregate
            for (auto g : d.groups) {
                g->safe_merge_to(ag);
            }
        });
        return ag;
    }
};

inline metric_group::metric_group()   { global.push_back(this); }
inline metric_group::~metric_group()  { global.remove(this); }

// scoped timer convenience

template <class MG>
class time_op_base {
protected:
    using clock_type = timer::clock_type;

    MG &_mg;
    std::string _name;
    clock_type::time_point _start;
    bool _stopped = false;

    template <typename ...Args>
        time_op_base(MG &mg, Args&& ...args)
            : _mg(mg),
              _name(metric_path(std::forward<Args>(args)...)),
              _start(clock_type::now()) {}

    time_op_base(const time_op_base &) = delete;
    time_op_base & operator = (const time_op_base &) = delete;

    time_op_base(time_op_base &&) = default;
    time_op_base & operator = (time_op_base &&) = default;
};

class time_op : public time_op_base<metric_group> {
public:
    template <typename ...Args>
        time_op(metric_group &mg, Args&& ...args)
            : time_op_base(mg, std::forward<Args>(args)...) {}

    template <typename ...Args>
        time_op(Args&& ...args)
            : time_op_base(*tls_metric_group.get(), std::forward<Args>(args)...) {}

    ~time_op() {
        stop();
    }
    void stop() {
        // can't stop more than once
        if (_stopped) return;
        _stopped = true;
        const auto dur = clock_type::now() - _start;
        metric_group::mg_lock lk(_mg);
        _mg.get<timer>(_name).update(dur);
    }
};

// use only when you are safe from multithreading
class map_time_op : public time_op_base<metric_map> {
public:
    template <typename ...Args>
        map_time_op(metric_map &mm, Args&& ...args)
            : time_op_base(mm, std::forward<Args>(args)...) {}

    ~map_time_op() {
        stop();
    }
    void stop() {
        // can't stop more than once
        if (_stopped) return;
        _stopped = true;
        const auto dur = clock_type::now() - _start;
        get<timer>(_mg, _name).update(dur);
    }
};

} // end namespace metrics
} // end namespace ten

#endif
<|endoftext|>


<commit_before>#if !defined(_TSXX_PORTS_HPP_)
#define _TSXX_PORTS_HPP_

#include <tsxx/interfaces.hpp>
#include <tsxx/registers.hpp>
#include <tsxx/system.hpp>

namespace tsxx
{
namespace ports
{

// WordPort
template <class WordReg, class CopyableMemoryRegion = tsxx::system::memory_region_window> class
wordport
{
public:
	wordport(CopyableMemoryRegion region)
		: mem(region), reg(mem.get_pointer())
	{
	}

	wordport(CopyableMemoryRegion region, unsigned int param)
		: mem(region), reg(mem.get_pointer(), param)
	{
	}

	// Force data access using the "strb" instruction -- don't rely on
	// compiler optimization by using pointers.
	inline void
	write(typename WordReg::word_type word)
	{
		reg.write(word);
	}

	inline typename WordReg::word_type
	read()
	{
		return reg.read();
	}

	typedef typename WordReg::word_type word_type;

protected:
	CopyableMemoryRegion mem;
	WordReg reg;

};

template <class WordPort> class
bitport
	: public tsxx::interfaces::binport
{
public:
	bitport(WordPort port, unsigned int bitno)
		: wordport(port), mask(1 << bitno)
	{
	}

	inline void
	unset()
	{
		write(false);
	}

	// Force data access using the "strh" instruction -- don't rely on
	// compiler optimization by using pointers.
	inline void
	set()
	{
		write(true);
	}

	inline bool
	get()
	{
		return read();
	}

protected:
	void
	write(bool state)
	{
		typename WordPort::word_type dat = wordport.read();

		if (state)
			dat |= mask;
		else
			dat &= ~mask;

		wordport.write(dat);
	}

	bool
	read()
	{
		return (wordport.read() & mask) == mask;
	}

private:
	WordPort wordport;
	const typename WordPort::word_type mask;

};

typedef wordport<tsxx::registers::reg8> port8;
typedef wordport<tsxx::registers::reg16> port16;
typedef wordport<tsxx::registers::reg32> port32;
typedef bitport<port8> bport8;
typedef bitport<port16> bport16;
typedef bitport<port32> bport32;

// WordPort
/**
 * DIO (GPIO) port class.
 */
template <class WordPort> class
dioport
{
public:
	dioport(WordPort data, WordPort dir)
		: data_port(data), ddr_port(dir)
	{
	}

	/**
	 * Sets the DIO pins direction.
	 *
	 * @param dir The direction of each pin: bits with 1 sets pin for
	 * output and with 0 for input.
	 */
	void
	set_dir(typename WordPort::word_type dir)
	{
		ddr_port.write(dir);
	}

	typename WordPort::word_type
	get_dir()
	{
		return ddr_port.read();
	}

	void
	write(typename WordPort::word_type word)
	{
		data_port.write(word);
	}

	typename WordPort::word_type
	read()
	{
		return data_port.read();
	}

public:
	WordPort &
	get_data_port()
	{
		return data_port;
	}

private:
	WordPort data_port;
	WordPort ddr_port;

};

}
}

#endif // !defined(_TSXX_PORTS_HPP_)
<commit_msg>Removed "CopyableMemoryRegion" from the "wordport" template parameters and removed port copy in "binport".<commit_after>#if !defined(_TSXX_PORTS_HPP_)
#define _TSXX_PORTS_HPP_

#include <tsxx/interfaces.hpp>
#include <tsxx/registers.hpp>
#include <tsxx/system.hpp>

namespace
tsxx
{

namespace
ports
{

template <class WordReg> class
wordport
{
public:
	wordport(tsxx::system::memory_region_window region)
		: mem(region), reg(mem.get_pointer())
	{
	}

	wordport(tsxx::system::memory_region_window region, unsigned int param)
		: mem(region), reg(mem.get_pointer(), param)
	{
	}

	// WordPort
public:
	typedef typename WordReg::word_type word_type;

	inline void
	write(word_type word)
	{
		reg.write(word);
	}

	inline word_type
	read()
	{
		return reg.read();
	}

protected:
	tsxx::system::memory_region_window mem;
	WordReg reg;

};

template <class WordPort> class
bitport
	: public tsxx::interfaces::binport
{
public:
	bitport(WordPort &port, unsigned int bitno)
		: wordport(port), mask(1 << bitno)
	{
	}

	inline void
	unset()
	{
		write(false);
	}

	inline void
	set()
	{
		write(true);
	}

	inline bool
	get()
	{
		return read();
	}

protected:
	void
	write(bool state)
	{
		typename WordPort::word_type dat = wordport.read();

		if (state)
			dat |= mask;
		else
			dat &= ~mask;

		wordport.write(dat);
	}

	bool
	read()
	{
		return (wordport.read() & mask) == mask;
	}

private:
	WordPort &wordport;
	const typename WordPort::word_type mask;

};

typedef wordport<tsxx::registers::reg8> port8;
typedef wordport<tsxx::registers::reg16> port16;
typedef wordport<tsxx::registers::reg32> port32;
typedef bitport<port8> bport8;
typedef bitport<port16> bport16;
typedef bitport<port32> bport32;

/**
 * DIO (GPIO) port class.
 */
template <class WordPort> class
dioport
{
public:
	dioport(WordPort data, WordPort dir)
		: data_port(data), ddr_port(dir)
	{
	}

	// WordPort
public:
	typedef typename WordPort::word_type word_type;

	void
	write(word_type word)
	{
		get_data_port().write(word);
	}

	word_type
	read()
	{
		return get_data_port().read();
	}

public:
	/**
	 * Sets the DIO pins direction.
	 *
	 * @param dir The direction of each pin: bits with 1 sets pin for
	 * output and with 0 for input.
	 */
	void
	set_dir(word_type dir)
	{
		ddr_port.write(dir);
	}

	word_type
	get_dir()
	{
		return ddr_port.read();
	}

public:
	inline WordPort &
	get_data_port()
	{
		return data_port;
	}

private:
	WordPort data_port;
	WordPort ddr_port;

};

}
}

#endif // !defined(_TSXX_PORTS_HPP_)
<|endoftext|>


<commit_before>/**
 * @file  unique_ptr.hpp
 * @brief unique_ptr is a fake implementation to use in place of a C++11 std::unique_ptr when compiling on an older compiler.
 *
 * @see http://www.cplusplus.com/reference/memory/unique_ptr/
 *
 * Copyright (c) 2014 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#pragma once

#include <cstddef>      // NULL
#include <algorithm>    // std::swap

// can be replaced by other error mechanism
#include <cassert>
#define SHARED_ASSERT(x)    assert(x)

/**
 * @brief fake implementation to use in place of a C++11 std::move() when compiling on an older compiler.
 *
 * @see http://www.cplusplus.com/reference/utility/move/
*/
template <typename T>
inline T& move(T& v)
{
    return v;
}

/**
 * @brief minimal implementation of smart pointer, a subset of the C++11 std::unique_ptr or boost::unique_ptr.
 *
 * unique_ptr is a smart pointer retaining ownership of an object through a provided pointer,
 * and sharing this ownership with a reference counter.
 * It destroys the object when the last shared pointer pointing to it is destroyed or reset.
 */
template<class T>
class unique_ptr
{
public:
    /// The type of the managed object, aliased as member type
    typedef T element_type;

    /// @brief Default constructor
    unique_ptr(void) throw() : // never throws
        px(NULL)
    {
    }
    /// @brief Constructor with the provided pointer to manage
    explicit unique_ptr(T* p) throw() : // never throws
        px(p)
    {
    }
    /// @brief Copy constructor to convert from another pointer type
    /* TODO MSVC error C2248: 'unique_ptr<B>::px' : unique_ptr<A> cannot access private member declared in class 'unique_ptr<B>'
    template <class U>
    unique_ptr(const unique_ptr<U>& ptr) throw() : // never throws
        px(static_cast<typename unique_ptr<T>::element_type*>(ptr.px))
    {
        const_cast<unique_ptr<U>&>(ptr).px = NULL; // const-cast to force ownership transfer!
    }
    */
    /// @brief Copy constructor (used by the copy-and-swap idiom)
    unique_ptr(const unique_ptr& ptr) throw() : // never throws
        px(ptr.px)
    {
        const_cast<unique_ptr&>(ptr).px = NULL; // const-cast to force ownership transfer!
    }
    /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
    unique_ptr& operator=(unique_ptr ptr) throw() // never throws
    {
        swap(ptr);
        return *this;
    }
    /// @brief the destructor releases its ownership and destroy the object
    inline ~unique_ptr(void) throw() // never throws
    {
        destroy();
    }
    /// @brief this reset releases its ownership and destroy the object
    inline void reset(void) throw() // never throws
    {
        destroy();
    }
    /// @brief this reset release its ownership and re-acquire another one
    void reset(T* p) throw() // never throws
    {
        SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed
        destroy();
        px = p;
    }

    /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
    void swap(unique_ptr& lhs) throw() // never throws
    {
        std::swap(px, lhs.px);
    }

    /// @brief release the ownership of the px pointer without destroying the object!
    inline void release(void) throw() // never throws
    {
        px = NULL;
    }

    // reference counter operations :
    inline operator bool() const throw() // never throws
    {
        return (NULL != px); // TODO nullptr
    }

    // underlying pointer operations :
    inline T& operator*()  const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return *px;
    }
    inline T* operator->() const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return px;
    }
    inline T* get(void)  const throw() // never throws
    {
        // no assert, can return NULL
        return px;
    }

private:
    /// @brief release the ownership of the px pointer and destroy the object
    inline void destroy(void) throw() // never throws
    {
        delete px;
        px = NULL;
    }

    /// @brief hack: const-cast release the ownership of the px pointer without destroying the object!
    inline void release(void) const throw() // never throws
    {
        px = NULL;
    }

private:
    T* px; //!< Native pointer
};

// comparaison operators
template<class T, class U> inline bool operator==(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() > r.get());
}

<commit_msg>Comments to explain the use of a fake unique_ptr<commit_after>/**
 * @file  unique_ptr.hpp
 * @brief unique_ptr is a fake implementation to use in place of a C++11 std::unique_ptr when compiling on an older compiler.
 *
 * @see http://www.cplusplus.com/reference/memory/unique_ptr/
 *
 * Copyright (c) 2014 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */
#pragma once

#include <cstddef>      // NULL
#include <algorithm>    // std::swap

// can be replaced by other error mechanism
#include <cassert>
#define SHARED_ASSERT(x)    assert(x)

/**
 * @brief fake implementation to use in place of a C++11 std::move() when compiling on an older compiler.
 *
 * @see http://www.cplusplus.com/reference/utility/move/
*/
template <typename T>
inline T& move(T& v)
{
    return v;
}

/**
 * @brief minimal implementation of unique pointer, a subset of the C++11 std::unique_ptr or boost::unique_ptr.
 *
 * unique_ptr is a smart pointer retaining ownership of an object through a provided pointer,
 * without the overhead of the shared_ptr reference counter.
 * It does not allow sharing this ownership (but moving it is possible)
 * and destroys the object when the pointer is destroyed or reset.
 *
 * This implementation is a fake one, to use when compiling on an older compiler that does not have the move semantic.
 * As such, it cannot offer any guaranty that the pointer is not copied!
 * It is still usable in production on such a compiler if you also compile
 * your program on a recent compiler to verify that it does not violate this guaranty.
 */
template<class T>
class unique_ptr
{
public:
    /// The type of the managed object, aliased as member type
    typedef T element_type;

    /// @brief Default constructor
    unique_ptr(void) throw() : // never throws
        px(NULL)
    {
    }
    /// @brief Constructor with the provided pointer to manage
    explicit unique_ptr(T* p) throw() : // never throws
        px(p)
    {
    }
    /// @brief Copy constructor to convert from another pointer type
    /* TODO MSVC error C2248: 'unique_ptr<B>::px' : unique_ptr<A> cannot access private member declared in class 'unique_ptr<B>'
    template <class U>
    unique_ptr(const unique_ptr<U>& ptr) throw() : // never throws
        px(static_cast<typename unique_ptr<T>::element_type*>(ptr.px))
    {
        const_cast<unique_ptr<U>&>(ptr).px = NULL; // const-cast to force ownership transfer!
    }
    */
    /// @brief Copy constructor (used by the copy-and-swap idiom)
    unique_ptr(const unique_ptr& ptr) throw() : // never throws
        px(ptr.px)
    {
        const_cast<unique_ptr&>(ptr).px = NULL; // const-cast to force ownership transfer!
    }
    /// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
    unique_ptr& operator=(unique_ptr ptr) throw() // never throws
    {
        swap(ptr);
        return *this;
    }
    /// @brief the destructor releases its ownership and destroy the object
    inline ~unique_ptr(void) throw() // never throws
    {
        destroy();
    }
    /// @brief this reset releases its ownership and destroy the object
    inline void reset(void) throw() // never throws
    {
        destroy();
    }
    /// @brief this reset release its ownership and re-acquire another one
    void reset(T* p) throw() // never throws
    {
        SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed
        destroy();
        px = p;
    }

    /// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
    void swap(unique_ptr& lhs) throw() // never throws
    {
        std::swap(px, lhs.px);
    }

    /// @brief release the ownership of the px pointer without destroying the object!
    inline void release(void) throw() // never throws
    {
        px = NULL;
    }

    // reference counter operations :
    inline operator bool() const throw() // never throws
    {
        return (NULL != px); // TODO nullptr
    }

    // underlying pointer operations :
    inline T& operator*()  const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return *px;
    }
    inline T* operator->() const throw() // never throws
    {
        SHARED_ASSERT(NULL != px);
        return px;
    }
    inline T* get(void)  const throw() // never throws
    {
        // no assert, can return NULL
        return px;
    }

private:
    /// @brief release the ownership of the px pointer and destroy the object
    inline void destroy(void) throw() // never throws
    {
        delete px;
        px = NULL;
    }

    /// @brief hack: const-cast release the ownership of the px pointer without destroying the object!
    inline void release(void) const throw() // never throws
    {
        px = NULL;
    }

private:
    T* px; //!< Native pointer
};

// comparaison operators
template<class T, class U> inline bool operator==(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() == r.get());
}
template<class T, class U> inline bool operator!=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() != r.get());
}
template<class T, class U> inline bool operator<=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() <= r.get());
}
template<class T, class U> inline bool operator<(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() < r.get());
}
template<class T, class U> inline bool operator>=(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() >= r.get());
}
template<class T, class U> inline bool operator>(const unique_ptr<T>& l, const unique_ptr<U>& r) throw() // never throws
{
    return (l.get() > r.get());
}

<|endoftext|>


<commit_before>/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_UTIL_ARRAY_HPP
#define PIC_UTIL_ARRAY_HPP

#include <vector>
#include <math.h>

namespace pic {

/**
 * @brief The Array class
 */
template<class T>
class Array
{
public:
    T *data;
    int nData;

    /**
     * @brief Array
     */
    Array()
    {
    }

    /**
     * @brief Array
     * @param n
     */
    Array(int n)
    {
        allocate(n);
    }

    /**
     * @brief Array
     * @param data
     * @param nData
     * @param bShallow
     */
    Array(T *data, int nData, bool bShallow)
    {
        this->nData = nData;

        if(bShallow) {
            this->data = data;
        } else {
            this->data = new T[nData];
            memcpy(this->data, data, sizeof(T) * nData);
        }
    }

    /**
     * @brief allocate
     * @param n
     */
    void allocate(int n)
    {
        if(n < 1) {
            return;
        }

        data = new T[n];
        this->nData = n;
    }

    /**
     * @brief release
     */
    void release()
    {
        if(nData > 0 && data != NULL) {
            delete[] data;
            data = NULL;
            nData = -1;
        }
    }

    /**
     * @brief genValue
     * @param value
     * @param n
     * @param ret
     * @return
     */
    static T* genValue(T value, int n, T *ret)
    {
        if(n < 1) {
            return ret;
        }

        if(ret == NULL) {
            ret = new T[n];
        }

        for(int i = 0; i < n; i++) {
            ret[i] = value;
        }

        return ret;
    }

    /**
     * @brief genRange
     * @param minVal
     * @param step
     * @param maxVal
     * @param ret
     */
    static T *genRange(T minVal, T step, T maxVal, T *ret, int &n)
    {
        n = int((maxVal - minVal) / step) + 1;

        if(ret == NULL) {
            ret = new T[n];
        }

        ret[0] = minVal;
        for(int i = 1; i < n; i++) {
            ret[i] = ret[i - 1] + step;
        }

        return ret;
    }

    /**
     * @brief linspace
     * @param minVal
     * @param maxVal
     * @param n
     * @param ret
     * @return
     */
    static T *linspace(T minVal, T maxVal, int n, T *ret)
    {
        T step = (maxVal - minVal) / (n - 1);
        int tmp = n;

        return genRange(minVal, step, maxVal, ret, tmp);
    }

    /**
     * @brief distanceSq
     * @param data0
     * @param data1
     * @param n
     * @return
     */
    static inline T distanceSq(T *data0, T *data1, int n)
    {
        T tmp = data0[0] - data1[0];
        T distSq = tmp * tmp;

        for(int k = 1; k < n; k++) {
            tmp = data0[k] - data1[k];
            distSq += tmp * tmp;
        }

        return distSq;
    }

    /**
     * @brief zeros
     * @param n
     * @return
     */
    static inline T* zeros(int n)
    {
        T *ret = new T[n];
        assign(T(0), ret, n);

        return ret;
    }

    /**
     * @brief norm_sq
     * @param data
     * @param n
     * @return
     */
    static inline T norm_sq(float *data, int n)
    {
        T n_sq = T(0);

        for(int k = 0; k < n; k++) {
            T tmp = data[k];
            n_sq += tmp * tmp;
        }

        return n_sq;
    }

    /**
     * @brief norm
     * @param data
     * @param n
     * @return
     */
    static inline float norm(float *data, int n)
    {
        float norm = 0.0f;

        for(int k = 0; k < n; k++) {
            float tmp = data[k];
            norm += tmp * tmp;
        }

        return sqrtf(norm);
    }

    /**
     * @brief normalize
     * @param data
     * @param n
     * @param norm
     * @return
     */
    static inline float normalize(float *data, int n, float norm = -1.0f)
    {

        if(norm < 0.0f) {
            norm = Array<float>::norm(data, n);
        }

        if(norm > 0.0f) {
            norm = sqrtf(norm);

            for(int k = 0; k < n; k++) {
                data[k] /= norm;
            }
        }

        return norm;
    }

    /**
     * @brief dot
     * @param data0
     * @param data1
     * @param n
     * @return
     */
    static inline T dot(T *data0, T *data1, int n)
    {
        T out = data0[0] * data1[0];

        for(int k = 1; k < n; k++) {
            out += data0[k] * data1[k];
        }

        return out;
    }

    /**
     * @brief mul
     * @param vec
     * @param size
     * @param scale
     * @return
     */
    static inline void mul(T *vec, int size, T scale)
    {
        if(vec == NULL || size < 1) {
            return;
        }

        for(int i = 0; i < size; i++) {
            vec[i] *= scale;
        }
    }

    /**
     * @brief mul
     * @param data
     * @param size
     * @param ret
     * @return
     */
    static inline void mul(T *data, int size, T *ret)
    {
        if(data == NULL || size < 1 || ret == NULL) {
            return;
        }

        for(int i = 0; i < size; i++) {
            ret[i] *= data[i];
        }
    }

    /**
     * @brief add
     * @param data
     * @param size
     * @param ret
     */
    static inline T* add(T *data, int size, T *ret)
    {
        for(int i = 0; i < size; i++) {
            ret[i] += data[i];
        }

        return ret;
    }

    /**
     * @brief div
     * @param data
     * @param size
     * @param value
     */
    static inline void div(T *data, int size, T value)
    {
        for(int i = 0; i < size; i++) {
            data[i] /= value;
        }
    }

    /**
     * @brief getMean
     * @param data
     * @param size
     * @param ind
     * @return
     */
    static inline T getMean(T *data, int size)
    {
        if(data == NULL || size < 1) {
            return T(0);
        }

        T ret = data[0];

        for(int i = 1; i < size; i++) {
            ret += data[i];
        }

        ret /= T(size);

        return ret;
    }

    /**
     * @brief getVariance
     * @param data
     * @param size
     * @return
     */
    static inline T getVariance(T *data, int size)
    {
        T mu = getMean(data, size);

        T tmp = data[0] - mu;
        T ret = tmp * tmp;

        for(int i = 1; i < size; i++) {
            tmp = data[i] - mu;
            ret += tmp * tmp;
        }

        return ret / T(size);
    }

    /**
     * @brief sum
     * @param data
     * @param size
     * @return
     */
    static inline T sum(T *data, int size)
    {
        if(data == NULL || size < 1) {
            return T(0);
        }

        T ret = data[0];

        for(int i = 1; i < size; i++) {
            ret += data[i];
        }

        return ret;
    }

    /**
     * @brief cumsum
     * @param vec
     * @param size
     * @param ret
     * @return
     */
    static inline T *cumsum(T *vec, int size, T *ret)
    {
        if(vec == NULL || size < 1) {
            return NULL;
        }

        if(ret == NULL) {
            ret = new T[size];
        }

        ret[0] = vec[0];

        for(int i = 1; i < size; i++) {
            ret[i] = vec[i] + ret[i - 1];
        }

        return ret;
    }

    /**
     * @brief assign
     * @param data
     * @param size
     * @param ret
     * @return
     */
    static inline T* assign (T* data, int size, T* ret)
    {
        memcpy(ret, data, sizeof(T) * size);
        return ret;
    }

    /**
     * @brief assign
     * @param data
     * @param ret
     * @param size
     * @return
     */
    static inline T* assign (T data, T* ret, int size)
    {
        for(int i = 0; i < size; i++) {
            ret[i] = data;
        }
        return ret;
    }

    /**
     * @brief apply
     * @param data
     * @param size
     * @param ret
     * @return
     */
    static inline T* apply(T *data,  int size, T *ret, T(*func)(T))
    {
        if(data == NULL || size < 1) {
            return ret;
        }

        if(ret == NULL) {
            ret = new T[size];
        }

        for(int i = 1; i < size; i++) {
            ret[i] = func(data[i]);
        }

        return ret;
    }

    /**
     * @brief getMax
     * @param data
     * @param size
     * @param ind
     * @return
     */
    static inline T getMax(T *data, int size, int &ind)
    {
        if(data == NULL || size < 1) {
            return T(size + 1);
        }

        T ret = data[0];
        ind = 0;

        for(int i = 1; i < size; i++) {
            if(ret < data[i]) {
                ret = data[i];
                ind = i;
            }
        }

        return ret;
    }

    /**
     * @brief getMin
     * @param data
     * @param size
     * @param ind
     * @return
     */
    static inline T getMin(T *data, int size, int &ind)
    {
        if(data == NULL || size < 1) {
            return T(size + 1);
        }

        T ret = data[0];
        ind = 0;

        for(int i = 1; i < size; i++) {
            if(ret > data[i]) {
                ret = data[i];
                ind = i;
            }
        }

        return ret;
    }

    /**
     * @brief interp linearly interpolates x and y data
     * @param x
     * @param y
     * @param size the size of x and y
     * @param xval
     * @return
     */
    static inline T interp(T *x, T *y, int size, T xval)
    {
        int sm1 = size - 1;
        if((xval >= x[0]) && (xval <= x[sm1])) {
            int offset2;
            T *ptr = std::lower_bound(&x[0], &x[sm1], xval);
            int offset = MAX(0, (int)(ptr - x - 1));

            if(offset == sm1) {
                offset2 = offset;
                offset  = offset2 - 1;
            } else {
                offset2 = MIN(size - 1, offset + 1);
            }

            T t = (xval - x[offset]) / (x[offset2] - x[offset]);

            return y[offset] * (T(1) - t) + t * y[offset2];
        } else {
            if(xval > x[sm1]) {
                int sm2 = size - 2;
                T t = (xval - x[sm2]) / (x[sm1] - x[sm2]);
                return t * (y[sm1] - y[sm2])  + y[sm2];
            } else {
                T t = (xval - x[0]) / (x[1] - x[0]);
                return t * (y[1] - y[0])  + y[0];
            }
        }

    }
};

/**
 * @brief Arrayf
 */
typedef	Array<float> Arrayf;

/**
 * @brief Arrayi
 */
typedef	Array<int> Arrayi;

/**
 * @brief Arrayui
 */
typedef	Array<unsigned int> Arrayui;

} // end namespace pic

#endif /* PIC_UTIL_ARRAY_HPP */

<commit_msg>Update array.hpp<commit_after>/*

PICCANTE
The hottest HDR imaging library!
http://vcg.isti.cnr.it/piccante

Copyright (C) 2014
Visual Computing Laboratory - ISTI CNR
http://vcg.isti.cnr.it
First author: Francesco Banterle

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

*/

#ifndef PIC_UTIL_ARRAY_HPP
#define PIC_UTIL_ARRAY_HPP

#include <vector>
#include <math.h>

namespace pic {

/**
 * @brief The Array class
 */
template<class T>
class Array
{
public:
    T *data;
    int nData;

    /**
     * @brief Array
     */
    Array()
    {
    }

    /**
     * @brief Array
     * @param n
     */
    Array(int n)
    {
        allocate(n);
    }

    /**
     * @brief Array
     * @param data
     * @param nData
     * @param bShallow
     */
    Array(T *data, int nData, bool bShallow)
    {
        this->nData = nData;

        if(bShallow) {
            this->data = data;
        } else {
            this->data = new T[nData];
            memcpy(this->data, data, sizeof(T) * nData);
        }
    }

    /**
     * @brief allocate
     * @param n
     */
    void allocate(int n)
    {
        if(n < 1) {
            return;
        }

        data = new T[n];
        this->nData = n;
    }

    /**
     * @brief release
     */
    void release()
    {
        if(nData > 0 && data != NULL) {
            delete[] data;
            data = NULL;
            nData = -1;
        }
    }

    /**
     * @brief genValue
     * @param value
     * @param n
     * @param ret
     * @return
     */
    static T* genValue(T value, int n, T *ret)
    {
        if(n < 1) {
            return ret;
        }

        if(ret == NULL) {
            ret = new T[n];
        }

        for(int i = 0; i < n; i++) {
            ret[i] = value;
        }

        return ret;
    }

    /**
     * @brief genRange
     * @param minVal
     * @param step
     * @param maxVal
     * @param ret
     */
    static T *genRange(T minVal, T step, T maxVal, T *ret, int &n)
    {
        n = int((maxVal - minVal) / step) + 1;

        if(ret == NULL) {
            ret = new T[n];
        }

        ret[0] = minVal;
        for(int i = 1; i < n; i++) {
            ret[i] = ret[i - 1] + step;
        }

        return ret;
    }

    /**
     * @brief linspace
     * @param minVal
     * @param maxVal
     * @param n
     * @param ret
     * @return
     */
    static T *linspace(T minVal, T maxVal, int n, T *ret)
    {
        T step = (maxVal - minVal) / (n - 1);
        int tmp = n;

        return genRange(minVal, step, maxVal, ret, tmp);
    }

    /**
     * @brief distanceSq
     * @param data0
     * @param data1
     * @param n
     * @return
     */
    static inline T distanceSq(T *data0, T *data1, int n)
    {
        T tmp = data0[0] - data1[0];
        T distSq = tmp * tmp;

        for(int k = 1; k < n; k++) {
            tmp = data0[k] - data1[k];
            distSq += tmp * tmp;
        }

        return distSq;
    }

    /**
     * @brief zeros
     * @param n
     * @return
     */
    static inline T* zeros(int n)
    {
        T *ret = new T[n];
        assign(T(0), ret, n);

        return ret;
    }

    /**
     * @brief norm_sq
     * @param data
     * @param n
     * @return
     */
    static inline T norm_sq(float *data, int n)
    {
        T n_sq = T(0);

        for(int k = 0; k < n; k++) {
            T tmp = data[k];
            n_sq += tmp * tmp;
        }

        return n_sq;
    }

    /**
     * @brief norm
     * @param data
     * @param n
     * @return
     */
    static inline float norm(float *data, int n)
    {
        float norm = 0.0f;

        for(int k = 0; k < n; k++) {
            float tmp = data[k];
            norm += tmp * tmp;
        }

        return sqrtf(norm);
    }

    /**
     * @brief normalize
     * @param data
     * @param n
     * @param norm
     * @return
     */
    static inline float normalize(float *data, int n, float norm = -1.0f)
    {

        if(norm < 0.0f) {
            norm = Array<float>::norm(data, n);
        }

        if(norm > 0.0f) {
            norm = sqrtf(norm);

            for(int k = 0; k < n; k++) {
                data[k] /= norm;
            }
        }

        return norm;
    }

    /**
     * @brief dot
     * @param data0
     * @param data1
     * @param n
     * @return
     */
    static inline T dot(T *data0, T *data1, int n)
    {
        T out = data0[0] * data1[0];

        for(int k = 1; k < n; k++) {
            out += data0[k] * data1[k];
        }

        return out;
    }

    /**
     * @brief mul
     * @param vec
     * @param size
     * @param scale
     * @return
     */
    static inline void mul(T *vec, int size, T scale)
    {
        if(vec == NULL || size < 1) {
            return;
        }

        for(int i = 0; i < size; i++) {
            vec[i] *= scale;
        }
    }

    /**
     * @brief mul
     * @param data
     * @param size
     * @param ret
     * @return
     */
    static inline void mul(T *data, int size, T *ret)
    {
        if(data == NULL || size < 1 || ret == NULL) {
            return;
        }

        for(int i = 0; i < size; i++) {
            ret[i] *= data[i];
        }
    }

    /**
     * @brief add
     * @param data
     * @param size
     * @param ret
     */
    static inline T* add(T *data, int size, T *ret)
    {
        for(int i = 0; i < size; i++) {
            ret[i] += data[i];
        }

        return ret;
    }

    /**
     * @brief div
     * @param data
     * @param size
     * @param value
     */
    static inline void div(T *data, int size, T value)
    {
        for(int i = 0; i < size; i++) {
            data[i] /= value;
        }
    }

    /**
     * @brief getMean
     * @param data
     * @param size
     * @param ind
     * @return
     */
    static inline T getMean(T *data, int size)
    {
        if(data == NULL || size < 1) {
            return T(0);
        }

        T ret = data[0];

        for(int i = 1; i < size; i++) {
            ret += data[i];
        }

        ret /= T(size);

        return ret;
    }

    /**
     * @brief getVariance
     * @param data
     * @param size
     * @return
     */
    static inline T getVariance(T *data, int size)
    {
        T mu = getMean(data, size);

        T tmp = data[0] - mu;
        T ret = tmp * tmp;

        for(int i = 1; i < size; i++) {
            tmp = data[i] - mu;
            ret += tmp * tmp;
        }

        return ret / T(size);
    }

    /**
     * @brief sum
     * @param data
     * @param size
     * @return
     */
    static inline T sum(T *data, int size)
    {
        if(data == NULL || size < 1) {
            return T(0);
        }

        T ret = data[0];

        for(int i = 1; i < size; i++) {
            ret += data[i];
        }

        return ret;
    }

    /**
     * @brief cumsum
     * @param vec
     * @param size
     * @param ret
     * @return
     */
    static inline T *cumsum(T *vec, int size, T *ret)
    {
        if(vec == NULL || size < 1) {
            return NULL;
        }

        if(ret == NULL) {
            ret = new T[size];
        }

        ret[0] = vec[0];

        for(int i = 1; i < size; i++) {
            ret[i] = vec[i] + ret[i - 1];
        }

        return ret;
    }

    /**
     * @brief assign
     * @param data
     * @param size
     * @param ret
     * @return
     */
    static inline T* assign (T* data, int size, T* ret)
    {
        memcpy(ret, data, sizeof(T) * size);
        return ret;
    }

    /**
     * @brief assign
     * @param data
     * @param ret
     * @param size
     * @return
     */
    static inline T* assign (T data, T* ret, int size)
    {
        for(int i = 0; i < size; i++) {
            ret[i] = data;
        }
        return ret;
    }

    /**
     * @brief apply
     * @param data
     * @param size
     * @param ret
     * @return
     */
    static inline T* apply(T *data,  int size, T *ret, T(*func)(T))
    {
        if(data == NULL || size < 1) {
            return ret;
        }

        if(ret == NULL) {
            ret = new T[size];
        }

        for(int i = 1; i < size; i++) {
            ret[i] = func(data[i]);
        }

        return ret;
    }

    /**
     * @brief getMax
     * @param data
     * @param size
     * @param ind
     * @return
     */
    static inline T getMax(T *data, int size, int &ind)
    {
        if(data == NULL || size < 1) {
            return T(size + 1);
        }

        T ret = data[0];
        ind = 0;

        for(int i = 1; i < size; i++) {
            if(ret < data[i]) {
                ret = data[i];
                ind = i;
            }
        }

        return ret;
    }

    /**
     * @brief getMin
     * @param data
     * @param size
     * @param ind
     * @return
     */
    static inline T getMin(T *data, int size, int &ind)
    {
        if(data == NULL || size < 1) {
            return T(size + 1);
        }

        T ret = data[0];
        ind = 0;

        for(int i = 1; i < size; i++) {
            if(ret > data[i]) {
                ret = data[i];
                ind = i;
            }
        }

        return ret;
    }

    /**
     * @brief interp linearly interpolates x and y data
     * @param x
     * @param y
     * @param size the size of x and y
     * @param xval
     * @return
     */
    static inline T interp(T *x, T *y, int size, T xval)
    {
        int sm1 = size - 1;
        if((xval >= x[0]) && (xval <= x[sm1])) {
            int offset2;
            T *ptr = std::lower_bound(&x[0], &x[sm1], xval);
            int offset = MAX(0, (int)(ptr - x - 1));

            if(offset == sm1) {
                offset2 = offset;
                offset  = offset2 - 1;
            } else {
                offset2 = MIN(size - 1, offset + 1);
            }

            T t = (xval - x[offset]) / (x[offset2] - x[offset]);

            return y[offset] * (T(1) - t) + t * y[offset2];
        } else {
            if(xval > x[sm1]) {
                int sm2 = size - 2;
                T t = (xval - x[sm2]) / (x[sm1] - x[sm2]);
                return t * (y[sm1] - y[sm2])  + y[sm2];
            } else {
                T t = (xval - x[0]) / (x[1] - x[0]);
                return t * (y[1] - y[0])  + y[0];
            }
        }

    }

    /**
     * @brief binSearchLeft
     * @param data
     * @param key
     * @param low
     * @param high
     * @return
     */
    int binSearchLeft(T *data, T key, int low, int high)
    {
        if( (high < low) ||
            (key > data[high - 1]) ||
            (key < data[low]) ) {
            return -1;
        }

        int mid;
        while(low < high) {
            mid = low + ((high - low) / 2);

            if(data[mid] < key) {
                low = mid + 1;
            } else {
                high = mid;
            }

        }

        if((data[mid] > key) && (mid > 0)) {
            mid--;
        }

        return mid;
    }
};

/**
 * @brief Arrayf
 */
typedef	Array<float> Arrayf;

/**
 * @brief Arrayi
 */
typedef	Array<int> Arrayi;

/**
 * @brief Arrayui
 */
typedef	Array<unsigned int> Arrayui;

} // end namespace pic

#endif /* PIC_UTIL_ARRAY_HPP */

<|endoftext|>


<commit_before>/**
 * @file kernel_pca_test.cpp
 * @author Ajinkya Kale <kaleajinkya@gmail.com>
 *
 * Test file for Kernel PCA.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/kernels/linear_kernel.hpp>
#include <mlpack/methods/kernel_pca/kernel_pca.hpp>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(KernelPCATest);

using namespace mlpack;
using namespace mlpack::kpca;
using namespace std;
using namespace arma;

BOOST_AUTO_TEST_CASE(linear_kernel)
{

  mat data("1 0 2 3 9;"
            "5 2 8 4 8;"
            "6 7 3 1 8");

  kpca::KernelPCA<kernel::LinearKernel> p;
  p.Apply(data, 2); // Reduce to 2 dimensions.

  // Compare with correct results.
  mat correct("-1.53781086 -3.51358020 -0.16139887 -1.87706634  7.08985628;"
               " 1.29937798  3.45762685 -2.69910005 -3.15620704  1.09830225");

  // If the eigenvectors are pointed opposite directions, they will cancel
  // each other out in this summation.
  for(size_t i = 0; i < data.n_rows; i++)
  {
    if (fabs(correct(i, 1) + data(i,1)) < 0.001 /* arbitrary */)
    {
         // Flip Armadillo coefficients for this column.
         data.row(i) *= -1;
    }
  }

  for (size_t row = 0; row < 2; row++)
    for (size_t col = 0; col < 5; col++)
      BOOST_REQUIRE_CLOSE(data(row, col), correct(row, col), 1e-3);
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>A couple changes to the kernel PCA test.<commit_after>/**
 * @file kernel_pca_test.cpp
 * @author Ajinkya Kale <kaleajinkya@gmail.com>
 *
 * Test file for Kernel PCA.
 */
#include <mlpack/core.hpp>
#include <mlpack/core/kernels/linear_kernel.hpp>
#include <mlpack/methods/kernel_pca/kernel_pca.hpp>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(KernelPCATest);

using namespace mlpack;
using namespace mlpack::kpca;
using namespace mlpack::kernel;
using namespace std;
using namespace arma;

BOOST_AUTO_TEST_CASE(linear_kernel)
{

  mat data("1 0 2 3 9;"
            "5 2 8 4 8;"
            "6 7 3 1 8");

  KernelPCA<LinearKernel> p;
  p.Apply(data, 2); // Reduce to 2 dimensions.

  // Compare with correct results.
  mat correct("-1.53781086 -3.51358020 -0.16139887 -1.87706634  7.08985628;"
              " 1.29937798  3.45762685 -2.69910005 -3.15620704  1.09830225");

  // If the eigenvectors are pointed opposite directions, they will cancel
  // each other out in this summation.
  for(size_t i = 0; i < data.n_rows; i++)
  {
    if (fabs(correct(i, 1) + data(i, 1)) < 0.001 /* arbitrary */)
    {
         // Flip eigenvector for this column (negate output).
         data.row(i) *= -1;
    }
  }

  for (size_t row = 0; row < 2; ++row)
    for (size_t col = 0; col < 5; ++col)
      BOOST_REQUIRE_CLOSE(data(row, col), correct(row, col), 1e-3);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/*
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2010  Belledonne Communications SARL.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "module.hh"
#include "agent.hh"

using namespace ::std;

class ContactRouteInserter: public Module {
public:
	ContactRouteInserter(Agent *ag) :
		Module(ag) {

	}

	void onDeclare(GenericStruct *module_config) {
		ConfigItemDescriptor items[] = {
			{ Boolean, "masquerade-contacts-for-invites", "Hack for workarounding Nortel CS2k gateways bug.", "false" },
			{ Boolean, "insert-domain", "Masquerade domain in spite of IP.", "false" },
			config_item_end
		};
		module_config->addChildrenValues(items);
	}

	void onLoad(const GenericStruct *mc) {
		mCtRtParamName = string("CtRt") + getAgent()->getUniqueId();
		mMasqueradeInviteContacts = mc->get<ConfigBoolean>("masquerade-contacts-for-invites")->read();
		mInsertDomain =  mc->get<ConfigBoolean>("insert-domain")->read();
	}

	void onRequest(shared_ptr<RequestSipEvent> &ev) {
		const shared_ptr<MsgSip> &ms = ev->getMsgSip();
		sip_t *sip = ms->getSip();
		const sip_method_t rq_method=sip->sip_request->rq_method;

		if (rq_method== sip_method_register) {
			//rewrite the request uri to the domain
			//this assumes the domain is also the proxy
			sip->sip_request->rq_url->url_host = sip->sip_to->a_url->url_host;
			sip->sip_request->rq_url->url_port = sip->sip_to->a_url->url_port;
		}

		if (rq_method == sip_method_register || ((rq_method == sip_method_invite) && mMasqueradeInviteContacts)) {
			LOGD("Masquerading contact");
			masqueradeContact(ev);
		}

		if (rq_method != sip_method_register) {
			// check if request-uri contains a contact-route parameter,
			// so that we can route back to the client
			char ctrt[64];
			url_t *dest = sip->sip_request->rq_url;
			// now need to check if request uri has special param inserted
			// by contact-route-inserter module
			if (url_param(dest->url_params, mCtRtParamName.c_str(), ctrt, sizeof(ctrt))) {
				LOGD("Found a contact route parameter");
				rewriteReqUrlWithCtrt(dest, ctrt, ms->getHome());
			} else {
				LOGD("No countact route parameter found");
			}
		}
	}
	virtual void onResponse(shared_ptr<ResponseSipEvent> &ev) {
		const shared_ptr<MsgSip> &ms = ev->getMsgSip();
		sip_t *sip = ms->getSip();
		if (mMasqueradeInviteContacts && (sip->sip_cseq->cs_method == sip_method_invite || sip->sip_cseq->cs_method == sip_method_subscribe)) {
			masqueradeContact(ev);
		}
	}

private:
	/*add a parameter like "CtRt15.128.128.2=tcp:201.45.118.16:50025" in the contact, so that we know where is the client
	 when we later have to route an INVITE to him */
	void masqueradeContact(shared_ptr<SipEvent> ev) {
		const shared_ptr<MsgSip> &ms = ev->getMsgSip();
		sip_t *sip = ms->getSip();
		if (sip->sip_contact == NULL || sip->sip_contact->m_url == NULL) {
			LOGD("Sip contact or url is null");
			return;
		}

		//rewrite contact, put local host instead and store previous contact host in new parameter
		char ct_tport[32] = "udp";
		url_t *ct_url = sip->sip_contact->m_url;

		//grab the transport of the contact uri
		if (url_param(ct_url->url_params, "transport", ct_tport, sizeof(ct_tport)) > 0) {

		}

		// Create parameter
		ostringstream oss;
		oss << mCtRtParamName << "=" << ct_tport << ":" ;
		if (mInsertDomain) {
			// param=tport:domain
			oss << sip->sip_from->a_url->url_host;
		} else {
			// param=tport:ip_prev_hop:port_prev_hop
			oss << ct_url->url_host << ":" << url_port(ct_url);
		}
		string param(oss.str());

		// Add parameter
		SLOGD << "Rewriting contact with param [" << param << "]";
		if (url_param_add(ms->getHome(), ct_url, param.c_str())) {
			LOGE("Cannot insert url param [%s]", param.c_str());
		}

		/*masquerade the contact, so that later requests (INVITEs) come to us */
		const url_t*preferedRoute=getAgent()->getPreferredRouteUrl();
		ct_url->url_host = preferedRoute->url_host;
		ct_url->url_port = url_port(preferedRoute);
		ct_url->url_scheme=preferedRoute->url_scheme;
		ct_url->url_params = url_strip_param_string(su_strdup(ms->getHome(), ct_url->url_params), "transport");
		char tport_value[64];
		if (url_param(preferedRoute->url_params,"transport",tport_value,sizeof(tport_value))>0){
			char *lParam = su_sprintf(ms->getHome(), "transport=%s",tport_value);
			url_param_add(ms->getHome(),ct_url,lParam);
		}
		SLOGD << "Contact has been rewritten to " << url_as_string(ms->getHome(), ct_url);
	}

	void rewriteReqUrlWithCtrt(url_t *dest, char ctrt_param[64], su_home_t *home) {
		//first remove param
		dest->url_params = url_strip_param_string(su_strdup(home, dest->url_params), mCtRtParamName.c_str());

		//test and remove maddr param
		if (url_has_param(dest, "maddr")) {
			dest->url_params = url_strip_param_string(su_strdup(home, dest->url_params), "maddr");
		}

		//test and remove transport param
		if (url_has_param(dest, "transport")) {
			dest->url_params = url_strip_param_string(su_strdup(home, dest->url_params), "transport");
		}

		//second change dest to
		char* tend = strchr(ctrt_param, ':');
		if (!tend) {
			LOGD("Skipping url rewrite: first ':' not found");
			return;
		}

		const char* transport = su_strndup(home, ctrt_param, tend - ctrt_param);
		const url_t *paramurl = url_format(home, "sip:%s", tend +1);

		dest->url_host = paramurl->url_host; // move ownership
		dest->url_port = paramurl->url_port; // move ownership
		if (strcasecmp(transport, "udp") != 0) {
			char *t_param = su_sprintf(home, "transport=%s", transport);
			url_param_add(home, dest, t_param);
		}

		LOGD("Request url changed to %s", url_as_string(home, dest));
	}

	string mCtRtParamName;
	bool mMasqueradeInviteContacts;
	bool mInsertDomain;
	static ModuleInfo<ContactRouteInserter> sInfo;
};

ModuleInfo<ContactRouteInserter> ContactRouteInserter::sInfo("ContactRouteInserter", "The purpose of the ContactRouteInserter module is to masquerade the contact header of incoming registers that are not handled locally "
		"(think about flexisip used as a SBC gateway) in such a way that it is then possible to route back outgoing invites to the original address. "
		"It is a kind of similar mechanism as Record-Route, but for REGISTER.",
		ModuleInfoBase::ModuleOid::ContactRouteInserter);
<commit_msg>CtRt inserter: rework on registers + insert domain<commit_after>/*
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2010  Belledonne Communications SARL.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "module.hh"
#include "agent.hh"

using namespace ::std;

class ContactRouteInserter: public Module {
public:
	ContactRouteInserter(Agent *ag) :
		Module(ag) {

	}

	void onDeclare(GenericStruct *module_config) {
		ConfigItemDescriptor items[] = {
			{ Boolean, "masquerade-contacts-on-registers", "Masquerade register contacts with proxy address.", "true" },
			{ Boolean, "masquerade-contacts-for-invites", "Masquerade invite-related messages with proxy address.", "false" },
			{ Boolean, "insert-domain", "Masquerade register with from domain.", "false" },
			config_item_end
		};
		module_config->addChildrenValues(items);
	}

	void onLoad(const GenericStruct *mc) {
		mCtRtParamName = string("CtRt") + getAgent()->getUniqueId();
		mMasqueradeInvites = mc->get<ConfigBoolean>("masquerade-contacts-for-invites")->read();
		mMasqueradeRegisters = mc->get<ConfigBoolean>("masquerade-contacts-on-registers")->read();
		mInsertDomain =  mc->get<ConfigBoolean>("insert-domain")->read();
	}

	void onRequest(shared_ptr<RequestSipEvent> &ev) {
		const shared_ptr<MsgSip> &ms = ev->getMsgSip();
		sip_t *sip = ms->getSip();
		const sip_method_t rq_method=sip->sip_request->rq_method;

		if (mMasqueradeRegisters && rq_method== sip_method_register) {
			//rewrite the request uri to the domain
			//this assumes the domain is also the proxy
			sip->sip_request->rq_url->url_host = sip->sip_to->a_url->url_host;
			sip->sip_request->rq_url->url_port = sip->sip_to->a_url->url_port;
			LOGD("Masquerading contact");
			masqueradeContact(ev, mInsertDomain);
		} else if (mMasqueradeInvites && rq_method == sip_method_invite) {
			LOGD("Masquerading contact");
			masqueradeContact(ev);
		}

		if (rq_method != sip_method_register) {
			// check if request-uri contains a contact-route parameter,
			// so that we can route back to the client
			char ctrt[64];
			url_t *dest = sip->sip_request->rq_url;
			// now need to check if request uri has special param inserted
			// by contact-route-inserter module
			if (url_param(dest->url_params, mCtRtParamName.c_str(), ctrt, sizeof(ctrt))) {
				LOGD("Found a contact route parameter");
				rewriteReqUrlWithCtrt(dest, ctrt, ms->getHome());
			} else {
				LOGD("No countact route parameter found");
			}
		}
	}
	virtual void onResponse(shared_ptr<ResponseSipEvent> &ev) {
		const shared_ptr<MsgSip> &ms = ev->getMsgSip();
		sip_t *sip = ms->getSip();
		if (mMasqueradeInvites && (sip->sip_cseq->cs_method == sip_method_invite || sip->sip_cseq->cs_method == sip_method_subscribe)) {
			masqueradeContact(ev);
		}
	}

private:
	/*add a parameter like "CtRt15.128.128.2=tcp:201.45.118.16:50025" in the contact, so that we know where is the client
	 when we later have to route an INVITE to him */
	void masqueradeContact(shared_ptr<SipEvent> ev, bool insertDomain = false) {
		const shared_ptr<MsgSip> &ms = ev->getMsgSip();
		sip_t *sip = ms->getSip();
		if (sip->sip_contact == NULL || sip->sip_contact->m_url == NULL) {
			LOGD("Sip contact or url is null");
			return;
		}

		url_t *ct_url = sip->sip_contact->m_url;

		//grab the transport of the contact uri
		char ct_tport[32] = "udp";
		if (url_param(ct_url->url_params, "transport", ct_tport, sizeof(ct_tport)) > 0) {

		}

		// Create parameter
		string param = mCtRtParamName + "=" + ct_tport + ":";
		if (insertDomain) {
			// param=tport:domain
			param += sip->sip_from->a_url->url_host;
		} else {
			// param=tport:ip_prev_hop:port_prev_hop
			param += ct_url->url_host;
			param += ":";
			param += url_port(ct_url);
		}

		// Add parameter
		SLOGD << "Rewriting contact with param [" << param << "]";
		if (url_param_add(ms->getHome(), ct_url, param.c_str())) {
			LOGE("Cannot insert url param [%s]", param.c_str());
		}

		/*masquerade the contact, so that later requests (INVITEs) come to us */
		const url_t*preferedRoute=getAgent()->getPreferredRouteUrl();
		ct_url->url_host = preferedRoute->url_host;
		ct_url->url_port = url_port(preferedRoute);
		ct_url->url_scheme=preferedRoute->url_scheme;
		ct_url->url_params = url_strip_param_string(su_strdup(ms->getHome(), ct_url->url_params), "transport");
		char tport_value[64];
		if (url_param(preferedRoute->url_params,"transport",tport_value,sizeof(tport_value))>0){
			char *lParam = su_sprintf(ms->getHome(), "transport=%s",tport_value);
			url_param_add(ms->getHome(),ct_url,lParam);
		}
		SLOGD << "Contact has been rewritten to " << url_as_string(ms->getHome(), ct_url);
	}

	void rewriteReqUrlWithCtrt(url_t *dest, char ctrt_param[64], su_home_t *home) {
		//first remove param
		dest->url_params = url_strip_param_string(su_strdup(home, dest->url_params), mCtRtParamName.c_str());

		//test and remove maddr param
		if (url_has_param(dest, "maddr")) {
			dest->url_params = url_strip_param_string(su_strdup(home, dest->url_params), "maddr");
		}

		//test and remove transport param
		if (url_has_param(dest, "transport")) {
			dest->url_params = url_strip_param_string(su_strdup(home, dest->url_params), "transport");
		}

		//second change dest to
		char* tend = strchr(ctrt_param, ':');
		if (!tend) {
			LOGD("Skipping url rewrite: first ':' not found");
			return;
		}

		const char* transport = su_strndup(home, ctrt_param, tend - ctrt_param);
		const url_t *paramurl = url_format(home, "sip:%s", tend +1);

		dest->url_host = paramurl->url_host; // move ownership
		dest->url_port = paramurl->url_port; // move ownership
		if (strcasecmp(transport, "udp") != 0) {
			char *t_param = su_sprintf(home, "transport=%s", transport);
			url_param_add(home, dest, t_param);
		}

		LOGD("Request url changed to %s", url_as_string(home, dest));
	}

	string mCtRtParamName;
	bool mMasqueradeRegisters, mMasqueradeInvites;
	bool mInsertDomain;
	static ModuleInfo<ContactRouteInserter> sInfo;
};

ModuleInfo<ContactRouteInserter> ContactRouteInserter::sInfo("ContactRouteInserter", "The purpose of the ContactRouteInserter module is to masquerade the contact header of incoming registers that are not handled locally "
		"(think about flexisip used as a SBC gateway) in such a way that it is then possible to route back outgoing invites to the original address. "
		"It is a kind of similar mechanism as Record-Route, but for REGISTER.",
		ModuleInfoBase::ModuleOid::ContactRouteInserter);
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/view-frame.h"

#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>

#include <boost/process/io.hpp>

#include "gui/gnuplot.h"
#include "gui/job.h"
#include "gui/task-frame.h"
#include "gui/task.h"
#include "isdf/isdf.h"
#include "isdf/reader.h"

namespace flint {
namespace gui {

namespace {

enum {
	kColumnX,
	kColumnY1,
	kColumnY2,
	kColumnName,
	kColumnUuid,
	kColumnLabel,
	kColumnTitle
};

}

ViewFrame::ViewFrame(TaskFrame *parent, wxDataViewListCtrl &job_list)
	: wxFrame(parent, wxID_ANY, "View" /* FIXME */)
	, job_list_(job_list)
	, data_view_(new wxDataViewListCtrl(this, wxID_ANY))
	, legend_(new wxCheckBox(this, wxID_ANY, "Legend"))
	, log_x_(new wxCheckBox(this, wxID_ANY, "Log X"))
	, log_y1_(new wxCheckBox(this, wxID_ANY, "Log Y1"))
	, log_y2_(new wxCheckBox(this, wxID_ANY, "Log Y2"))
	, num_variables_(0)
	, skip_(0)
{
	data_view_->AppendToggleColumn("X");
	data_view_->AppendToggleColumn("Y1");
	data_view_->AppendToggleColumn("Y2");
	data_view_->AppendTextColumn("Name");
	data_view_->AppendTextColumn("UUID");
	data_view_->AppendTextColumn("Label");

	LoadVariables();

	legend_->SetValue(true);

	auto hbox = new wxBoxSizer(wxHORIZONTAL);
	hbox->Add(legend_);
	hbox->Add(log_x_);
	hbox->Add(log_y1_);
	hbox->Add(log_y2_);
	auto vbox = new wxBoxSizer(wxVERTICAL);
	vbox->Add(data_view_, 1 /* vertically stretchable */, wxEXPAND /* horizontally stretchable */);
	vbox->Add(hbox);
	data_view_->SetMinSize(wxSize(600, 300));
	SetSizerAndFit(vbox);

	legend_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	log_x_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	log_y1_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	log_y2_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ViewFrame::OnItemValueChanged, this);
	Bind(wxEVT_CLOSE_WINDOW, &ViewFrame::OnClose, this);
}

void ViewFrame::Plot()
{
	LineGraphOption option;
	option.legend = legend_->IsChecked();
	option.log_x = log_x_->IsChecked();
	option.log_y1 = log_y1_->IsChecked();
	option.log_y2 = log_y2_->IsChecked();

	wxDataViewItemArray arr;
	job_list_.GetSelections(arr);
	for (const auto &item : arr) {
		auto task_frame = wxDynamicCast(GetParent(), TaskFrame);
		Job job(task_frame->task(), job_list_.ItemToRow(item)+1);
		option.input_files.emplace(job.id, job.GetOutputFileName().GetFullPath());
	}

	option.x = -1;
	option.num_variables = num_variables_;
	option.skip = skip_;
	auto *store = data_view_->GetStore();
	wxVariant v;
	for (unsigned int i=0;i<store->GetItemCount();i++) {
		store->GetValueByRow(v, i, kColumnX);
		if (v.GetBool()) {
			option.x = static_cast<int>(i);
			continue;
		}
		store->GetValueByRow(v, i, kColumnY1);
		if (v.GetBool()) {
			store->GetValueByRow(v, i, kColumnTitle);
			option.y1.emplace(i, v.GetString());
			continue;
		}
		store->GetValueByRow(v, i, kColumnY2);
		if (v.GetBool()) {
			store->GetValueByRow(v, i, kColumnTitle);
			option.y2.emplace(i, v.GetString());
			continue;
		}
	}

	if (child_ && child_->valid() && child_->running()) {
		pipe_ << "clear" << std::endl;
		if (!pipe_) {
			wxLogError("failed to clear gnuplot window");
			return;
		}
	} else {
		// TODO: get gnuplot executable name from preference
		child_.reset(new boost::process::child("gnuplot", boost::process::std_in < pipe_));
		if (!child_->valid()) {
			wxLogError("failed to call gnuplot");
			return;
		}
	}
	PlotLineGraph(option, pipe_);
}

void ViewFrame::OnCheckBox(wxCommandEvent &)
{
	Plot();
}

void ViewFrame::OnItemValueChanged(wxDataViewEvent &event)
{
	Unbind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ViewFrame::OnItemValueChanged, this);
	int col = event.GetColumn();
	int row = data_view_->ItemToRow(event.GetItem());
	switch (col) {
	case kColumnX:
		if (data_view_->GetToggleValue(row, col)) {
			data_view_->SetToggleValue(false, row, kColumnY1);
			data_view_->SetToggleValue(false, row, kColumnY2);
			for (int i=0;i<data_view_->GetItemCount();i++) {
				if (i != row)
					data_view_->SetToggleValue(false, i, kColumnX);
			}
		}
		break;
	case kColumnY1:
		if (data_view_->GetToggleValue(row, col)) {
			data_view_->SetToggleValue(false, row, kColumnX);
			data_view_->SetToggleValue(false, row, kColumnY2);
		}
		break;
	case kColumnY2:
		if (data_view_->GetToggleValue(row, col)) {
			data_view_->SetToggleValue(false, row, kColumnX);
			data_view_->SetToggleValue(false, row, kColumnY1);
		}
		break;
	default:
		break;
	}
	Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ViewFrame::OnItemValueChanged, this);

	Plot();
}

void ViewFrame::OnClose(wxCloseEvent &)
{
	Show(false);
}

namespace {

class Handler {
public:
	Handler(wxDataViewListCtrl &data_view);

	void GetDescription(std::uint32_t i, std::uint32_t bytes, const char *d);

private:
	wxDataViewListCtrl &data_view_;
};

Handler::Handler(wxDataViewListCtrl &data_view)
	: data_view_(data_view)
{}

void Handler::GetDescription(std::uint32_t i, std::uint32_t bytes, const char *d)
{
	auto original_d = d;
	auto original_bytes = bytes;
	wxVector<wxVariant> data;
	data.push_back(i == 0);
	data.push_back(false);
	data.push_back(false);
	wxString uuid;
	wxString label;
	if (bytes > 36 && d[36] == ':') { // TODO
		uuid = wxString(d, 36u);
		d += 37;
		bytes -= 37;
	}
	for (std::uint32_t k=0;k<bytes;k++) {
		if (d[k] == '@') { // label found
			label = wxString(d+k+1, bytes-k-1);
			bytes = k;
		}
	}
	data.push_back(wxString(d, bytes));
	data.push_back(uuid);
	data.push_back(label);
	data.push_back(wxString(original_d, original_bytes));
	data_view_.AppendItem(data);
}

}

bool ViewFrame::LoadVariables()
{
	auto task_frame = wxDynamicCast(GetParent(), TaskFrame);
	auto filename = task_frame->task().GetDirectoryName();
	filename.SetFullName("isdh");
	wxString full_path = filename.GetFullPath();
	std::ifstream ifs(full_path.c_str(), std::ios::in|std::ios::binary);
	if (!ifs.is_open()) {
		wxLogError("failed to open %s", full_path);
		return false;
	}
	isdf::Reader reader;
	Handler handler(*data_view_);
	bool b = reader.ReadHeader(&ifs) && reader.SkipComment(&ifs) && reader.ReadDescriptions(handler, &ifs);
	if (!b) {
		ifs.close();
		wxLogError("failed to load variables from %s", full_path);
		return false;
	}
	ifs.close();
	num_variables_ = reader.num_objs();
	skip_ = sizeof(isdf::ISDFHeader) + reader.num_bytes_comment() + reader.num_bytes_descs() + reader.num_bytes_units();
	return true;
}

}
}
<commit_msg>Use the function for the purpose<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gui/view-frame.h"

#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>

#include <boost/process/io.hpp>

#include "gui/gnuplot.h"
#include "gui/job.h"
#include "gui/task-frame.h"
#include "gui/task.h"
#include "isdf/isdf.h"
#include "isdf/reader.h"

namespace flint {
namespace gui {

namespace {

enum {
	kColumnX,
	kColumnY1,
	kColumnY2,
	kColumnName,
	kColumnUuid,
	kColumnLabel,
	kColumnTitle
};

}

ViewFrame::ViewFrame(TaskFrame *parent, wxDataViewListCtrl &job_list)
	: wxFrame(parent, wxID_ANY, "View" /* FIXME */)
	, job_list_(job_list)
	, data_view_(new wxDataViewListCtrl(this, wxID_ANY))
	, legend_(new wxCheckBox(this, wxID_ANY, "Legend"))
	, log_x_(new wxCheckBox(this, wxID_ANY, "Log X"))
	, log_y1_(new wxCheckBox(this, wxID_ANY, "Log Y1"))
	, log_y2_(new wxCheckBox(this, wxID_ANY, "Log Y2"))
	, num_variables_(0)
	, skip_(0)
{
	data_view_->AppendToggleColumn("X");
	data_view_->AppendToggleColumn("Y1");
	data_view_->AppendToggleColumn("Y2");
	data_view_->AppendTextColumn("Name");
	data_view_->AppendTextColumn("UUID");
	data_view_->AppendTextColumn("Label");

	LoadVariables();

	legend_->SetValue(true);

	auto hbox = new wxBoxSizer(wxHORIZONTAL);
	hbox->Add(legend_);
	hbox->Add(log_x_);
	hbox->Add(log_y1_);
	hbox->Add(log_y2_);
	auto vbox = new wxBoxSizer(wxVERTICAL);
	vbox->Add(data_view_, 1 /* vertically stretchable */, wxEXPAND /* horizontally stretchable */);
	vbox->Add(hbox);
	data_view_->SetMinSize(wxSize(600, 300));
	SetSizerAndFit(vbox);

	legend_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	log_x_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	log_y1_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	log_y2_->Bind(wxEVT_CHECKBOX, &ViewFrame::OnCheckBox, this);
	Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ViewFrame::OnItemValueChanged, this);
	Bind(wxEVT_CLOSE_WINDOW, &ViewFrame::OnClose, this);
}

void ViewFrame::Plot()
{
	LineGraphOption option;
	option.legend = legend_->IsChecked();
	option.log_x = log_x_->IsChecked();
	option.log_y1 = log_y1_->IsChecked();
	option.log_y2 = log_y2_->IsChecked();

	wxDataViewItemArray arr;
	job_list_.GetSelections(arr);
	for (const auto &item : arr) {
		auto task_frame = wxDynamicCast(GetParent(), TaskFrame);
		Job job(task_frame->task(), job_list_.ItemToRow(item)+1);
		option.input_files.emplace(job.id, job.GetOutputFileName().GetFullPath());
	}

	option.x = -1;
	option.num_variables = num_variables_;
	option.skip = skip_;
	auto *store = data_view_->GetStore();
	wxVariant v;
	for (unsigned int i=0;i<store->GetItemCount();i++) {
		store->GetValueByRow(v, i, kColumnX);
		if (v.GetBool()) {
			option.x = static_cast<int>(i);
			continue;
		}
		store->GetValueByRow(v, i, kColumnY1);
		if (v.GetBool()) {
			store->GetValueByRow(v, i, kColumnTitle);
			option.y1.emplace(i, v.GetString());
			continue;
		}
		store->GetValueByRow(v, i, kColumnY2);
		if (v.GetBool()) {
			store->GetValueByRow(v, i, kColumnTitle);
			option.y2.emplace(i, v.GetString());
			continue;
		}
	}

	if (child_ && child_->valid() && child_->running()) {
		pipe_ << "clear" << std::endl;
		if (!pipe_) {
			wxLogError("failed to clear gnuplot window");
			return;
		}
	} else {
		// TODO: get gnuplot executable name from preference
		child_.reset(new boost::process::child("gnuplot", boost::process::std_in < pipe_));
		if (!child_->valid()) {
			wxLogError("failed to call gnuplot");
			return;
		}
	}
	PlotLineGraph(option, pipe_);
}

void ViewFrame::OnCheckBox(wxCommandEvent &)
{
	Plot();
}

void ViewFrame::OnItemValueChanged(wxDataViewEvent &event)
{
	Unbind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ViewFrame::OnItemValueChanged, this);
	int col = event.GetColumn();
	int row = data_view_->ItemToRow(event.GetItem());
	switch (col) {
	case kColumnX:
		if (data_view_->GetToggleValue(row, col)) {
			data_view_->SetToggleValue(false, row, kColumnY1);
			data_view_->SetToggleValue(false, row, kColumnY2);
			for (int i=0;i<data_view_->GetItemCount();i++) {
				if (i != row)
					data_view_->SetToggleValue(false, i, kColumnX);
			}
		}
		break;
	case kColumnY1:
		if (data_view_->GetToggleValue(row, col)) {
			data_view_->SetToggleValue(false, row, kColumnX);
			data_view_->SetToggleValue(false, row, kColumnY2);
		}
		break;
	case kColumnY2:
		if (data_view_->GetToggleValue(row, col)) {
			data_view_->SetToggleValue(false, row, kColumnX);
			data_view_->SetToggleValue(false, row, kColumnY1);
		}
		break;
	default:
		break;
	}
	Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, &ViewFrame::OnItemValueChanged, this);

	Plot();
}

void ViewFrame::OnClose(wxCloseEvent &)
{
	Show(false);
}

namespace {

class Handler {
public:
	Handler(wxDataViewListCtrl &data_view);

	void GetDescription(std::uint32_t i, std::uint32_t bytes, const char *d);

private:
	wxDataViewListCtrl &data_view_;
};

Handler::Handler(wxDataViewListCtrl &data_view)
	: data_view_(data_view)
{}

void Handler::GetDescription(std::uint32_t i, std::uint32_t bytes, const char *d)
{
	auto original_d = d;
	auto original_bytes = bytes;
	wxVector<wxVariant> data;
	data.push_back(i == 0);
	data.push_back(false);
	data.push_back(false);
	wxString uuid;
	wxString label;
	if (bytes > 36 && d[36] == ':') { // TODO
		uuid = wxString(d, 36u);
		d += 37;
		bytes -= 37;
	}
	for (std::uint32_t k=0;k<bytes;k++) {
		if (d[k] == '@') { // label found
			label = wxString(d+k+1, bytes-k-1);
			bytes = k;
		}
	}
	data.push_back(wxString(d, bytes));
	data.push_back(uuid);
	data.push_back(label);
	data.push_back(wxString(original_d, original_bytes));
	data_view_.AppendItem(data);
}

}

bool ViewFrame::LoadVariables()
{
	auto task_frame = wxDynamicCast(GetParent(), TaskFrame);
	auto filename = task_frame->task().GetDirectoryName();
	filename.SetFullName("isdh");
	wxString full_path = filename.GetFullPath();
	std::ifstream ifs(full_path.c_str(), std::ios::in|std::ios::binary);
	if (!ifs.is_open()) {
		wxLogError("failed to open %s", full_path);
		return false;
	}
	isdf::Reader reader;
	Handler handler(*data_view_);
	bool b = reader.ReadHeader(&ifs) && reader.SkipComment(&ifs) && reader.ReadDescriptions(handler, &ifs);
	if (!b) {
		ifs.close();
		wxLogError("failed to load variables from %s", full_path);
		return false;
	}
	ifs.close();
	num_variables_ = reader.num_objs();
	skip_ = reader.GetDataOffset();
	return true;
}

}
}
<|endoftext|>


<commit_before>#include "uspeech.h"
#include "math.h"

/**
 * Constructor
 */
signal::signal(int port){
	pin = port;
    fconstant = F_CONSTANT;
    econstant = 2;
    aconstant = 4;
    vconstant = 6;
    shconstant = 10;
    amplificationFactor = 10;
    micPowerThreshold = 50;
    scale = 1;
}
/**
 * Calibration of background based on averaging
 */
void signal::calibrate(){
#ifdef ARDUINO_ENVIRONMENT
    calib = 0;
    uint32_t samp=0;
    for (uint16_t ind=0; ind<10000; ind++) {
	//acquire background noise
	samp += analogRead(pin) * scale;
    }
    calib = samp/10000;
#endif
}
/**
 * Sampling of the sound: Based on storing values minus average background noise
 */
void signal::sample(){
	int i = 0;
	while ( i < 32){
#ifdef ARDUINO_ENVIRONMENT
		arr[i] = (analogRead(pin)*scale-calib);
#endif
		i++;
	}

}
/**
 * An estimate of background noise
 */
unsigned int signal::power(){
	unsigned int j = 0;
	uint8_t i = 0;
	while(i<32){
		j+=abs(arr[i]);
		i++;
	}
	return j;
}
/**
 * power/abs(sum of derivative)
 */
unsigned int signal::complexity(int power){
	unsigned int j = 0;
	uint8_t i = 1;
	while(i<32){
		j+=abs(arr[i]-arr[i-1]);
		i++;
	}
    //Serial.println(j);
	return (j*amplificationFactor)/power;
}

/**
* Point of maximum amplitude
*/
unsigned int signal::maxPower()
{
    int i =0;
    unsigned int max = 0;
    while (i<32){
        if(max<abs(arr[i])){
            max = abs(arr[i]);
            maxPos = i;
        }
        i++;
        avgPower+=arr[i];
    }
    avgPower /= 32;
    return max;
}
int signal::snr(int power){
	uint8_t i=0,j=0;
	int mean =power/32;
	while(i <32){
		j+=sq(arr[i]-mean);
		i++;
	}
	return sqrt(j/mean)/power;
}
<commit_msg>first commit<commit_after>#include "uspeech.h"
#include "math.h"

/**
 * Constructor
 */
signal::signal(int port){
	pin = port;
    fconstant = F_CONSTANT;
    econstant = 2;
    aconstant = 4;
    vconstant = 6;
    shconstant = 10;
    amplificationFactor = 10;
    micPowerThreshold = 50;
    scale = 1;
}
/**
 * Calibration of background based on averaging
 */
void signal::calibrate(){
#ifdef ARDUINO_ENVIRONMENT
    calib = 0;
    uint32_t samp=0;
    for (uint16_t ind=0; ind<10000; ind++) {
	//acquire background noise
	samp += analogRead(pin) * scale;
    }
    calib = samp/10000;
#endif
}
/**
 * Sampling of the sound: Based on storing values minus average background noise
 */
void signal::sample(){
	int i = 0;
	while ( i < 32){
#ifdef ARDUINO_ENVIRONMENT
		arr[i] = (analogRead(pin)*scale-calib);
#endif
		i++;
	}

}
/**
 * An estimate of background noise
 */
unsigned int signal::power(){
	unsigned int j = 0;
	uint8_t i = 0;
	while(i<32){
		j+=abs(arr[i]);
		i++;
	}
	return j;
}
/**
 * power/abs(sum of derivative)
 */
unsigned int signal::complexity(int power){
	unsigned int j = 0;
	uint8_t i = 1;
	while(i<32){
		j+=abs(arr[i]-arr[i-1]);
		i++;
	}
    //Serial.println(j);
	return (j*amplificationFactor)/power;
}

/**
* Point of maximum amplitude
*/
unsigned int signal::maxPower()
{
    int i =0;
    unsigned int max = 0;
    while (i<32){
        if(max<abs(arr[i])){
            max = abs(arr[i]);
            maxPos = i;
        }
        i++;
        avgPower+=arr[i];
    }
    avgPower /= 32;
    return max;
}
int signal::snr(int power){
	uint8_t i=0,j=0;
	int mean =power/32;
	while(i <32){
		j+=sqrt(arr[i]-mean);
		i++;
	}
	return sqrt(j/mean)/power;
}
<|endoftext|>