<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef SHARED_PTR_HH_
#define SHARED_PTR_HH_

#include <utility>
#include <type_traits>

template <typename T>
class lw_shared_ptr;

template <typename T>
class shared_ptr;

template <typename T>
class enable_lw_shared_from_this;

template <typename T>
class enable_shared_from_this;

template <typename T, typename... A>
lw_shared_ptr<T> make_lw_shared(A&&... a);

template <typename T>
lw_shared_ptr<T> make_lw_shared(T&& a);

template <typename T>
lw_shared_ptr<T> make_lw_shared(T& a);

template <typename T, typename... A>
shared_ptr<T> make_shared(A&&... a);

template <typename T, typename U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& p);

template <typename T, typename U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& p);

template <typename T, typename U>
shared_ptr<T> const_pointer_cast(const shared_ptr<U>& p);

// We want to support two use cases for shared_ptr<T>:
//
//   1. T is any type (primitive or class type)
//
//   2. T is a class type that inherits from enable_shared_from_this<T>.
//
// In the first case, we must wrap T in an object containing the counter,
// since T may be a primitive type and cannot be a base class.
//
// In the second case, we want T to reach the counter through its
// enable_shared_from_this<> base class, so that we can implement
// shared_from_this().
//
// To implement those two conflicting requirements (T alongside its counter;
// T inherits from an object containing the counter) we use std::conditional<>
// and some accessor functions to select between two implementations.

// CRTP from this to enable shared_from_this:
template <typename T>
class enable_lw_shared_from_this {
    long _count = 0;
    using ctor = T;
    T* to_value() { return static_cast<T*>(this); }
    T* to_internal_object() { return static_cast<T*>(this); }
protected:
    enable_lw_shared_from_this& operator=(const enable_lw_shared_from_this&) { return *this; }
    enable_lw_shared_from_this& operator=(enable_lw_shared_from_this&&) { return *this; }
public:
    lw_shared_ptr<T> shared_from_this();
    template <typename X>
    friend class lw_shared_ptr;
};

template <typename T>
struct shared_ptr_no_esft {
    long _count = 0;
    T _value;
    using ctor = shared_ptr_no_esft;

    T* to_value() { return &_value; }
    shared_ptr_no_esft* to_internal_object() { return this; }
    shared_ptr_no_esft() = default;
    shared_ptr_no_esft(const T& x) : _value(x) {}
    shared_ptr_no_esft(T&& x) : _value(std::move(x)) {}
    template <typename... A>
    shared_ptr_no_esft(A&&... a) : _value(std::forward<A>(a)...) {}
    template <typename X>
    friend class lw_shared_ptr;
};

template <typename T>
using shared_ptr_impl
    = std::conditional_t<
        std::is_base_of<enable_lw_shared_from_this<T>, T>::value,
        enable_lw_shared_from_this<T>,
        shared_ptr_no_esft<T>
      >;

template <typename T>
class lw_shared_ptr {
    mutable shared_ptr_impl<T>* _p = nullptr;
private:
    lw_shared_ptr(shared_ptr_impl<T>* p) : _p(p) {
        if (_p) {
            ++_p->_count;
        }
    }
    template <typename... A>
    static lw_shared_ptr make(A&&... a) {
        return lw_shared_ptr(new typename shared_ptr_impl<T>::ctor(std::forward<A>(a)...));
    }
public:
    using element_type = T;

    lw_shared_ptr() = default;
    lw_shared_ptr(const lw_shared_ptr& x) : _p(x._p) {
        if (_p) {
            ++_p->_count;
        }
    }
    lw_shared_ptr(lw_shared_ptr&& x) : _p(x._p) {
        x._p = nullptr;
    }
    ~lw_shared_ptr() {
        if (_p && !--_p->_count) {
            delete _p->to_internal_object();
        }
    }
    lw_shared_ptr& operator=(const lw_shared_ptr& x) {
        if (_p != x._p) {
            this->~lw_shared_ptr();
            new (this) lw_shared_ptr(x);
        }
        return *this;
    }
    lw_shared_ptr& operator=(lw_shared_ptr&& x) {
        if (_p != x._p) {
            this->~lw_shared_ptr();
            new (this) lw_shared_ptr(std::move(x));
        }
        return *this;
    }
    lw_shared_ptr& operator=(T&& x) {
        this->~lw_shared_ptr();
        new (this) lw_shared_ptr(make_lw_shared<T>(std::move(x)));
        return *this;
    }

    T& operator*() const { return *_p->to_value(); }
    T* operator->() const { return _p->to_value(); }
    T* get() const { return _p->to_value(); }

    long int use_count() {
        if (_p) {
            return _p->_count;
        } else {
            return 0;
        }
    }

    operator lw_shared_ptr<const T>() const {
        return lw_shared_ptr<const T>(_p);
    }

    explicit operator bool() const {
        return _p;
    }

    bool owned() const {
        return _p->_count == 1;
    }

    template <typename X, typename... A>
    friend lw_shared_ptr<X> make_lw_shared(A&&...);

    template <typename U>
    friend lw_shared_ptr<U> make_lw_shared(U&&);

    template <typename U>
    friend lw_shared_ptr<U> make_lw_shared(U&);

    template <typename U>
    friend class enable_lw_shared_from_this;
};

template <typename T, typename... A>
inline
lw_shared_ptr<T> make_lw_shared(A&&... a) {
    return lw_shared_ptr<T>::make(std::forward<A>(a)...);
}

template <typename T>
inline
lw_shared_ptr<T> make_lw_shared(T&& a) {
    return lw_shared_ptr<T>::make(std::move(a));
}

template <typename T>
inline
lw_shared_ptr<T> make_lw_shared(T& a) {
    return lw_shared_ptr<T>::make(a);
}

template <typename T>
inline
lw_shared_ptr<T>
enable_lw_shared_from_this<T>::shared_from_this() {
    return lw_shared_ptr<T>(this);
}

// Polymorphic shared pointer class

struct shared_ptr_count_base {
    // destructor is responsible for fully-typed deletion
    virtual ~shared_ptr_count_base() {}
    long count = 0;
};

template <typename T>
struct shared_ptr_count_for : shared_ptr_count_base {
    T data;
    template <typename... A>
    shared_ptr_count_for(A&&... a) : data(std::forward<A>(a)...) {}
};

template <typename T>
class enable_shared_from_this : private shared_ptr_count_base {
public:
    shared_ptr<T> shared_from_this();

    template <typename U>
    friend class shared_ptr;
};

template <typename T>
class shared_ptr {
    mutable shared_ptr_count_base* _b = nullptr;
    mutable T* _p = nullptr;
private:
    explicit shared_ptr(shared_ptr_count_for<T>* b) : _b(b), _p(&b->data) {
        ++_b->count;
    }
    shared_ptr(shared_ptr_count_for<T>* b, T* p) : _b(b), _p(p) {
        // test _p, not _b, since dynamic_pointer_cast<>() can zero p but not b
        if (_p) {
            ++_b->count;
        }
    }
    explicit shared_ptr(enable_shared_from_this<T>* p) : _b(p), _p(static_cast<T*>(p)) {
        if (_b) {
            ++_b->count;
        }
    }
public:
    shared_ptr() = default;
    shared_ptr(const shared_ptr& x)
            : _b(x._b)
            , _p(x._p) {
        if (_b) {
            ++_b->count;
        }
    }
    shared_ptr(shared_ptr&& x)
            : _b(x._b)
            , _p(x._p) {
        x._b = nullptr;
        x._p = nullptr;
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr(const shared_ptr<U>& x)
            : _b(x._b)
            , _p(x._p) {
        if (_b) {
            ++_b->count;
        }
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr(shared_ptr<U>&& x)
            : _b(x._b)
            , _p(x._p) {
        x._b = nullptr;
        x._p = nullptr;
    }
    ~shared_ptr() {
        if (_b && !--_b->count) {
            delete _b;
        }
    }
    shared_ptr& operator=(const shared_ptr& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(x);
        }
        return *this;
    }
    shared_ptr& operator=(shared_ptr&& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(std::move(x));
        }
        return *this;
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr& operator=(const shared_ptr<U>& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(x);
        }
        return *this;
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr& operator=(shared_ptr<U>&& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(std::move(x));
        }
        return *this;
    }
    explicit operator bool() const {
        return _p;
    }
    T& operator*() const{
        return *_p;
    }
    T* operator->() const {
        return _p;
    }
    T* get() const {
        return _p;
    }

    template <bool esft>
    struct make_helper;

    template <typename U, typename... A>
    friend shared_ptr<U> make_shared(A&&... a);

    template <typename V, typename U>
    friend shared_ptr<V> static_pointer_cast(const shared_ptr<U>& p);

    template <typename V, typename U>
    friend shared_ptr<V> dynamic_pointer_cast(const shared_ptr<U>& p);

    template <typename V, typename U>
    friend shared_ptr<V> const_pointer_cast(const shared_ptr<U>& p);

    template <bool esft, typename... A>
    static shared_ptr make(A&&... a);

    template <typename U>
    friend class enable_shared_from_this;

    template <typename U, bool esft>
    friend struct shared_ptr_make_helper;
};

template <typename U, bool esft>
struct shared_ptr_make_helper;

template <typename T>
struct shared_ptr_make_helper<T, false> {
    template <typename... A>
    static shared_ptr<T> make(A&&... a) {
        return shared_ptr<T>(new shared_ptr_count_for<T>(std::forward<A>(a)...));
    }
};

template <typename T>
struct shared_ptr_make_helper<T, true> {
    template <typename... A>
    static shared_ptr<T> make(A&&... a) {
        return shared_ptr<T>(new T(std::forward<A>(a)...));
    }
};

template <typename T, typename... A>
inline
shared_ptr<T>
make_shared(A&&... a) {
    using helper = shared_ptr_make_helper<T, std::is_base_of<enable_shared_from_this<T>, T>::value>;
    return helper::make(std::forward<A>(a)...);
}

template <typename T, typename U>
inline
shared_ptr<T>
static_pointer_cast(const shared_ptr<U>& p) {
    return shared_ptr<T>(p->_b, static_cast<T*>(p._p));
}

template <typename T, typename U>
inline
shared_ptr<T>
dynamic_pointer_cast(const shared_ptr<U>& p) {
    return shared_ptr<T>(p->_b, dynamic_cast<T*>(p._p));
}

template <typename T, typename U>
inline
shared_ptr<T>
const_pointer_cast(const shared_ptr<U>& p) {
    return shared_ptr<T>(p->_b, const_cast<T*>(p._p));
}

template <typename T>
inline
shared_ptr<T>
enable_shared_from_this<T>::shared_from_this() {
    return shared_ptr<T>(this);
}

#endif /* SHARED_PTR_HH_ */
<commit_msg>shared_ptr: add some documentation<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef SHARED_PTR_HH_
#define SHARED_PTR_HH_

#include <utility>
#include <type_traits>

// This header defines two shared pointer facilities, lw_shared_ptr<> and
// shared_ptr<>, both modeled after std::shared_ptr<>.
//
// Unlike std::shared_ptr<>, neither of these implementations are thread
// safe, and two pointers sharing the same object must not be used in
// different threads.
//
// lw_shared_ptr<> is the more lightweight variant, with a lw_shared_ptr<>
// occupying just one machine word, and adding just one word to the shared
// object.  However, it does not support polymorphism.
//
// shared_ptr<> is more expensive, with a pointer occupying two machine
// words, and with two words of overhead in the shared object.  In return,
// it does support polymorphism.
//
// Both variants support shared_from_this() via enable_shared_from_this<>
// and lw_enable_shared_from_this<>().
//

template <typename T>
class lw_shared_ptr;

template <typename T>
class shared_ptr;

template <typename T>
class enable_lw_shared_from_this;

template <typename T>
class enable_shared_from_this;

template <typename T, typename... A>
lw_shared_ptr<T> make_lw_shared(A&&... a);

template <typename T>
lw_shared_ptr<T> make_lw_shared(T&& a);

template <typename T>
lw_shared_ptr<T> make_lw_shared(T& a);

template <typename T, typename... A>
shared_ptr<T> make_shared(A&&... a);

template <typename T, typename U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& p);

template <typename T, typename U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& p);

template <typename T, typename U>
shared_ptr<T> const_pointer_cast(const shared_ptr<U>& p);

// We want to support two use cases for shared_ptr<T>:
//
//   1. T is any type (primitive or class type)
//
//   2. T is a class type that inherits from enable_shared_from_this<T>.
//
// In the first case, we must wrap T in an object containing the counter,
// since T may be a primitive type and cannot be a base class.
//
// In the second case, we want T to reach the counter through its
// enable_shared_from_this<> base class, so that we can implement
// shared_from_this().
//
// To implement those two conflicting requirements (T alongside its counter;
// T inherits from an object containing the counter) we use std::conditional<>
// and some accessor functions to select between two implementations.

// CRTP from this to enable shared_from_this:
template <typename T>
class enable_lw_shared_from_this {
    long _count = 0;
    using ctor = T;
    T* to_value() { return static_cast<T*>(this); }
    T* to_internal_object() { return static_cast<T*>(this); }
protected:
    enable_lw_shared_from_this& operator=(const enable_lw_shared_from_this&) { return *this; }
    enable_lw_shared_from_this& operator=(enable_lw_shared_from_this&&) { return *this; }
public:
    lw_shared_ptr<T> shared_from_this();
    template <typename X>
    friend class lw_shared_ptr;
};

template <typename T>
struct shared_ptr_no_esft {
    long _count = 0;
    T _value;
    using ctor = shared_ptr_no_esft;

    T* to_value() { return &_value; }
    shared_ptr_no_esft* to_internal_object() { return this; }
    shared_ptr_no_esft() = default;
    shared_ptr_no_esft(const T& x) : _value(x) {}
    shared_ptr_no_esft(T&& x) : _value(std::move(x)) {}
    template <typename... A>
    shared_ptr_no_esft(A&&... a) : _value(std::forward<A>(a)...) {}
    template <typename X>
    friend class lw_shared_ptr;
};

template <typename T>
using shared_ptr_impl
    = std::conditional_t<
        std::is_base_of<enable_lw_shared_from_this<T>, T>::value,
        enable_lw_shared_from_this<T>,
        shared_ptr_no_esft<T>
      >;

template <typename T>
class lw_shared_ptr {
    mutable shared_ptr_impl<T>* _p = nullptr;
private:
    lw_shared_ptr(shared_ptr_impl<T>* p) : _p(p) {
        if (_p) {
            ++_p->_count;
        }
    }
    template <typename... A>
    static lw_shared_ptr make(A&&... a) {
        return lw_shared_ptr(new typename shared_ptr_impl<T>::ctor(std::forward<A>(a)...));
    }
public:
    using element_type = T;

    lw_shared_ptr() = default;
    lw_shared_ptr(const lw_shared_ptr& x) : _p(x._p) {
        if (_p) {
            ++_p->_count;
        }
    }
    lw_shared_ptr(lw_shared_ptr&& x) : _p(x._p) {
        x._p = nullptr;
    }
    ~lw_shared_ptr() {
        if (_p && !--_p->_count) {
            delete _p->to_internal_object();
        }
    }
    lw_shared_ptr& operator=(const lw_shared_ptr& x) {
        if (_p != x._p) {
            this->~lw_shared_ptr();
            new (this) lw_shared_ptr(x);
        }
        return *this;
    }
    lw_shared_ptr& operator=(lw_shared_ptr&& x) {
        if (_p != x._p) {
            this->~lw_shared_ptr();
            new (this) lw_shared_ptr(std::move(x));
        }
        return *this;
    }
    lw_shared_ptr& operator=(T&& x) {
        this->~lw_shared_ptr();
        new (this) lw_shared_ptr(make_lw_shared<T>(std::move(x)));
        return *this;
    }

    T& operator*() const { return *_p->to_value(); }
    T* operator->() const { return _p->to_value(); }
    T* get() const { return _p->to_value(); }

    long int use_count() {
        if (_p) {
            return _p->_count;
        } else {
            return 0;
        }
    }

    operator lw_shared_ptr<const T>() const {
        return lw_shared_ptr<const T>(_p);
    }

    explicit operator bool() const {
        return _p;
    }

    bool owned() const {
        return _p->_count == 1;
    }

    template <typename X, typename... A>
    friend lw_shared_ptr<X> make_lw_shared(A&&...);

    template <typename U>
    friend lw_shared_ptr<U> make_lw_shared(U&&);

    template <typename U>
    friend lw_shared_ptr<U> make_lw_shared(U&);

    template <typename U>
    friend class enable_lw_shared_from_this;
};

template <typename T, typename... A>
inline
lw_shared_ptr<T> make_lw_shared(A&&... a) {
    return lw_shared_ptr<T>::make(std::forward<A>(a)...);
}

template <typename T>
inline
lw_shared_ptr<T> make_lw_shared(T&& a) {
    return lw_shared_ptr<T>::make(std::move(a));
}

template <typename T>
inline
lw_shared_ptr<T> make_lw_shared(T& a) {
    return lw_shared_ptr<T>::make(a);
}

template <typename T>
inline
lw_shared_ptr<T>
enable_lw_shared_from_this<T>::shared_from_this() {
    return lw_shared_ptr<T>(this);
}

// Polymorphic shared pointer class

struct shared_ptr_count_base {
    // destructor is responsible for fully-typed deletion
    virtual ~shared_ptr_count_base() {}
    long count = 0;
};

template <typename T>
struct shared_ptr_count_for : shared_ptr_count_base {
    T data;
    template <typename... A>
    shared_ptr_count_for(A&&... a) : data(std::forward<A>(a)...) {}
};

template <typename T>
class enable_shared_from_this : private shared_ptr_count_base {
public:
    shared_ptr<T> shared_from_this();

    template <typename U>
    friend class shared_ptr;
};

template <typename T>
class shared_ptr {
    mutable shared_ptr_count_base* _b = nullptr;
    mutable T* _p = nullptr;
private:
    explicit shared_ptr(shared_ptr_count_for<T>* b) : _b(b), _p(&b->data) {
        ++_b->count;
    }
    shared_ptr(shared_ptr_count_for<T>* b, T* p) : _b(b), _p(p) {
        // test _p, not _b, since dynamic_pointer_cast<>() can zero p but not b
        if (_p) {
            ++_b->count;
        }
    }
    explicit shared_ptr(enable_shared_from_this<T>* p) : _b(p), _p(static_cast<T*>(p)) {
        if (_b) {
            ++_b->count;
        }
    }
public:
    shared_ptr() = default;
    shared_ptr(const shared_ptr& x)
            : _b(x._b)
            , _p(x._p) {
        if (_b) {
            ++_b->count;
        }
    }
    shared_ptr(shared_ptr&& x)
            : _b(x._b)
            , _p(x._p) {
        x._b = nullptr;
        x._p = nullptr;
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr(const shared_ptr<U>& x)
            : _b(x._b)
            , _p(x._p) {
        if (_b) {
            ++_b->count;
        }
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr(shared_ptr<U>&& x)
            : _b(x._b)
            , _p(x._p) {
        x._b = nullptr;
        x._p = nullptr;
    }
    ~shared_ptr() {
        if (_b && !--_b->count) {
            delete _b;
        }
    }
    shared_ptr& operator=(const shared_ptr& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(x);
        }
        return *this;
    }
    shared_ptr& operator=(shared_ptr&& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(std::move(x));
        }
        return *this;
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr& operator=(const shared_ptr<U>& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(x);
        }
        return *this;
    }
    template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
    shared_ptr& operator=(shared_ptr<U>&& x) {
        if (this != &x) {
            this->~shared_ptr();
            new (this) shared_ptr(std::move(x));
        }
        return *this;
    }
    explicit operator bool() const {
        return _p;
    }
    T& operator*() const{
        return *_p;
    }
    T* operator->() const {
        return _p;
    }
    T* get() const {
        return _p;
    }

    template <bool esft>
    struct make_helper;

    template <typename U, typename... A>
    friend shared_ptr<U> make_shared(A&&... a);

    template <typename V, typename U>
    friend shared_ptr<V> static_pointer_cast(const shared_ptr<U>& p);

    template <typename V, typename U>
    friend shared_ptr<V> dynamic_pointer_cast(const shared_ptr<U>& p);

    template <typename V, typename U>
    friend shared_ptr<V> const_pointer_cast(const shared_ptr<U>& p);

    template <bool esft, typename... A>
    static shared_ptr make(A&&... a);

    template <typename U>
    friend class enable_shared_from_this;

    template <typename U, bool esft>
    friend struct shared_ptr_make_helper;
};

template <typename U, bool esft>
struct shared_ptr_make_helper;

template <typename T>
struct shared_ptr_make_helper<T, false> {
    template <typename... A>
    static shared_ptr<T> make(A&&... a) {
        return shared_ptr<T>(new shared_ptr_count_for<T>(std::forward<A>(a)...));
    }
};

template <typename T>
struct shared_ptr_make_helper<T, true> {
    template <typename... A>
    static shared_ptr<T> make(A&&... a) {
        return shared_ptr<T>(new T(std::forward<A>(a)...));
    }
};

template <typename T, typename... A>
inline
shared_ptr<T>
make_shared(A&&... a) {
    using helper = shared_ptr_make_helper<T, std::is_base_of<enable_shared_from_this<T>, T>::value>;
    return helper::make(std::forward<A>(a)...);
}

template <typename T, typename U>
inline
shared_ptr<T>
static_pointer_cast(const shared_ptr<U>& p) {
    return shared_ptr<T>(p->_b, static_cast<T*>(p._p));
}

template <typename T, typename U>
inline
shared_ptr<T>
dynamic_pointer_cast(const shared_ptr<U>& p) {
    return shared_ptr<T>(p->_b, dynamic_cast<T*>(p._p));
}

template <typename T, typename U>
inline
shared_ptr<T>
const_pointer_cast(const shared_ptr<U>& p) {
    return shared_ptr<T>(p->_b, const_cast<T*>(p._p));
}

template <typename T>
inline
shared_ptr<T>
enable_shared_from_this<T>::shared_from_this() {
    return shared_ptr<T>(this);
}

#endif /* SHARED_PTR_HH_ */
<|endoftext|>


<commit_before>/*************************************************************************/
/*  undo_redo.cpp                                                        */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "undo_redo.h"

void UndoRedo::_discard_redo() {

	if (current_action==actions.size()-1)
		return;

	for(int i=current_action+1;i<actions.size();i++) {

		for (List<Operation>::Element *E=actions[i].do_ops.front();E;E=E->next()) {

			if (E->get().type==Operation::TYPE_REFERENCE) {

				Object *obj = ObjectDB::get_instance(E->get().object);
				if (obj)
					memdelete(obj);
			}
		}
		//ERASE do data
	}

	actions.resize(current_action+1);

}

void UndoRedo::create_action(const String& p_name,bool p_mergeable) {

	if (action_level==0) {

		_discard_redo();
		if (p_mergeable && actions.size() && actions[actions.size()-1].name==p_name) {

			//old will replace new (it's mergeable after all)
			// should check references though!
			current_action=actions.size()-2;
			actions[current_action+1].do_ops.clear();
			//actions[current_action+1].undo_ops.clear(); - no, this is kept
			merging=true;

		} else {
			Action new_action;
			new_action.name=p_name;
			actions.push_back(new_action);
			merging=false;
		}
	}

	action_level++;
}

void UndoRedo::add_do_method(Object *p_object,const String& p_method,VARIANT_ARG_DECLARE) {

	VARIANT_ARGPTRS
	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation do_op;
	do_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	do_op.type=Operation::TYPE_METHOD;
	do_op.name=p_method;

	for(int i=0;i<VARIANT_ARG_MAX;i++) {
		do_op.args[i]=*argptr[i];
	}
	actions[current_action+1].do_ops.push_back(do_op);
}

void UndoRedo::add_undo_method(Object *p_object,const String& p_method,VARIANT_ARG_DECLARE) {

	VARIANT_ARGPTRS
	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	if (merging)
		return; //- no undo if merging

	Operation undo_op;
	undo_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	undo_op.type=Operation::TYPE_METHOD;
	undo_op.name=p_method;

	for(int i=0;i<VARIANT_ARG_MAX;i++) {
		undo_op.args[i]=*argptr[i];
	}
	actions[current_action+1].undo_ops.push_back(undo_op);

}
void UndoRedo::add_do_property(Object *p_object,const String& p_property,const Variant& p_value) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation do_op;
	do_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	do_op.type=Operation::TYPE_PROPERTY;
	do_op.name=p_property;
	do_op.args[0]=p_value;
	actions[current_action+1].do_ops.push_back(do_op);

}
void UndoRedo::add_undo_property(Object *p_object,const String& p_property,const Variant& p_value) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());

	Operation undo_op;
	undo_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	undo_op.type=Operation::TYPE_PROPERTY;
	undo_op.name=p_property;
	undo_op.args[0]=p_value;
	actions[current_action+1].undo_ops.push_back(undo_op);

}
void UndoRedo::add_do_reference(Object *p_object) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation do_op;
	do_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	do_op.type=Operation::TYPE_REFERENCE;
	actions[current_action+1].do_ops.push_back(do_op);

}
void UndoRedo::add_undo_reference(Object *p_object) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation undo_op;
	undo_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	undo_op.type=Operation::TYPE_REFERENCE;
	actions[current_action+1].undo_ops.push_back(undo_op);

}

void UndoRedo::_pop_history_tail() {

	_discard_redo();

	if (!actions.size())
		return;

	for (List<Operation>::Element *E=actions[0].undo_ops.front();E;E=E->next()) {

		if (E->get().type==Operation::TYPE_REFERENCE) {

			Object *obj = ObjectDB::get_instance(E->get().object);
			if (obj)
				memdelete(obj);
		}
	}

	actions.remove(0);
	current_action--;
}

void UndoRedo::commit_action() {

	ERR_FAIL_COND(action_level<=0);
	action_level--;
	if (action_level>0)
		return; //still nested

	redo(); // perform action

	if (max_steps>0 && actions.size()>max_steps) {
		//clear early steps

		while(actions.size() > max_steps)
			_pop_history_tail();

	}

	if (callback && actions.size()>0) {
		callback(callback_ud,actions[actions.size()-1].name);
	}
}

void UndoRedo::_process_operation_list(List<Operation>::Element *E) {

	for (;E;E=E->next()) {

		Operation &op=E->get();

		Object *obj = ObjectDB::get_instance(op.object);
		if (!obj) {
			//corruption
			clear_history();
			ERR_FAIL_COND(!obj);

		}
		switch(op.type) {

			case Operation::TYPE_METHOD: {

				obj->call(op.name,VARIANT_ARGS_FROM_ARRAY(op.args));
			} break;
			case Operation::TYPE_PROPERTY: {

				obj->set(op.name,op.args[0]);
#ifdef TOOLS_ENABLED
				Resource* res = obj->cast_to<Resource>();
				if (res)
					res->set_edited(true);
#endif
			} break;
			case Operation::TYPE_REFERENCE: {
				//do nothing
			} break;

		}
	}
}

void UndoRedo::redo() {

	ERR_FAIL_COND(action_level>0);

	if ((current_action+1)>=actions.size())
		return; //nothing to redo
	current_action++;

	_process_operation_list(actions[current_action].do_ops.front());
	version++;
}

void UndoRedo::undo() {

	ERR_FAIL_COND(action_level>0);
	if (current_action<0)
		return; //nothing to redo
	_process_operation_list(actions[current_action].undo_ops.front());
	current_action--;
}

void UndoRedo::clear_history() {

	ERR_FAIL_COND(action_level>0);
	_discard_redo();

	while(actions.size())
		_pop_history_tail();

	version++;
}

String UndoRedo::get_current_action_name() const {

	ERR_FAIL_COND_V(action_level>0,"");
	if (current_action<0)
		return ""; //nothing to redo
	return actions[current_action].name;
}

void UndoRedo::set_max_steps(int p_max_steps) {

	max_steps=p_max_steps;
}

int UndoRedo::get_max_steps() const {

	return max_steps;
}

uint64_t UndoRedo::get_version() const {

	return version;
}

void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback,void* p_ud) {

	callback=p_callback;
	callback_ud=p_ud;
}

UndoRedo::UndoRedo() {

	version=0;
	action_level=0;
	current_action=-1;
	max_steps=-1;
	merging=true;
	callback=NULL;
	callback_ud=NULL;
}

UndoRedo::~UndoRedo() {

	clear_history();
}
<commit_msg>-shadergraph now saved when on external file and modified,  fixes #1832<commit_after>/*************************************************************************/
/*  undo_redo.cpp                                                        */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "undo_redo.h"

void UndoRedo::_discard_redo() {

	if (current_action==actions.size()-1)
		return;

	for(int i=current_action+1;i<actions.size();i++) {

		for (List<Operation>::Element *E=actions[i].do_ops.front();E;E=E->next()) {

			if (E->get().type==Operation::TYPE_REFERENCE) {

				Object *obj = ObjectDB::get_instance(E->get().object);
				if (obj)
					memdelete(obj);
			}
		}
		//ERASE do data
	}

	actions.resize(current_action+1);

}

void UndoRedo::create_action(const String& p_name,bool p_mergeable) {

	if (action_level==0) {

		_discard_redo();
		if (p_mergeable && actions.size() && actions[actions.size()-1].name==p_name) {

			//old will replace new (it's mergeable after all)
			// should check references though!
			current_action=actions.size()-2;
			actions[current_action+1].do_ops.clear();
			//actions[current_action+1].undo_ops.clear(); - no, this is kept
			merging=true;

		} else {
			Action new_action;
			new_action.name=p_name;
			actions.push_back(new_action);
			merging=false;
		}
	}

	action_level++;
}

void UndoRedo::add_do_method(Object *p_object,const String& p_method,VARIANT_ARG_DECLARE) {

	VARIANT_ARGPTRS
	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation do_op;
	do_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	do_op.type=Operation::TYPE_METHOD;
	do_op.name=p_method;

	for(int i=0;i<VARIANT_ARG_MAX;i++) {
		do_op.args[i]=*argptr[i];
	}
	actions[current_action+1].do_ops.push_back(do_op);
}

void UndoRedo::add_undo_method(Object *p_object,const String& p_method,VARIANT_ARG_DECLARE) {

	VARIANT_ARGPTRS
	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	if (merging)
		return; //- no undo if merging

	Operation undo_op;
	undo_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	undo_op.type=Operation::TYPE_METHOD;
	undo_op.name=p_method;

	for(int i=0;i<VARIANT_ARG_MAX;i++) {
		undo_op.args[i]=*argptr[i];
	}
	actions[current_action+1].undo_ops.push_back(undo_op);

}
void UndoRedo::add_do_property(Object *p_object,const String& p_property,const Variant& p_value) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation do_op;
	do_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	do_op.type=Operation::TYPE_PROPERTY;
	do_op.name=p_property;
	do_op.args[0]=p_value;
	actions[current_action+1].do_ops.push_back(do_op);

}
void UndoRedo::add_undo_property(Object *p_object,const String& p_property,const Variant& p_value) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());

	Operation undo_op;
	undo_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	undo_op.type=Operation::TYPE_PROPERTY;
	undo_op.name=p_property;
	undo_op.args[0]=p_value;
	actions[current_action+1].undo_ops.push_back(undo_op);

}
void UndoRedo::add_do_reference(Object *p_object) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation do_op;
	do_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	do_op.type=Operation::TYPE_REFERENCE;
	actions[current_action+1].do_ops.push_back(do_op);

}
void UndoRedo::add_undo_reference(Object *p_object) {

	ERR_FAIL_COND(action_level<=0);
	ERR_FAIL_COND((current_action+1)>=actions.size());
	Operation undo_op;
	undo_op.object=p_object->get_instance_ID();
	if (p_object->cast_to<Resource>())
		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>());

	undo_op.type=Operation::TYPE_REFERENCE;
	actions[current_action+1].undo_ops.push_back(undo_op);

}

void UndoRedo::_pop_history_tail() {

	_discard_redo();

	if (!actions.size())
		return;

	for (List<Operation>::Element *E=actions[0].undo_ops.front();E;E=E->next()) {

		if (E->get().type==Operation::TYPE_REFERENCE) {

			Object *obj = ObjectDB::get_instance(E->get().object);
			if (obj)
				memdelete(obj);
		}
	}

	actions.remove(0);
	current_action--;
}

void UndoRedo::commit_action() {

	ERR_FAIL_COND(action_level<=0);
	action_level--;
	if (action_level>0)
		return; //still nested

	redo(); // perform action

	if (max_steps>0 && actions.size()>max_steps) {
		//clear early steps

		while(actions.size() > max_steps)
			_pop_history_tail();

	}

	if (callback && actions.size()>0) {
		callback(callback_ud,actions[actions.size()-1].name);
	}
}

void UndoRedo::_process_operation_list(List<Operation>::Element *E) {

	for (;E;E=E->next()) {

		Operation &op=E->get();

		Object *obj = ObjectDB::get_instance(op.object);
		if (!obj) {
			//corruption
			clear_history();
			ERR_FAIL_COND(!obj);

		}

		switch(op.type) {

			case Operation::TYPE_METHOD: {

				obj->call(op.name,VARIANT_ARGS_FROM_ARRAY(op.args));
#ifdef TOOLS_ENABLED
				Resource* res = obj->cast_to<Resource>();
				if (res)
					res->set_edited(true);
#endif
			} break;
			case Operation::TYPE_PROPERTY: {

				obj->set(op.name,op.args[0]);
#ifdef TOOLS_ENABLED
				Resource* res = obj->cast_to<Resource>();
				if (res)
					res->set_edited(true);
#endif
			} break;
			case Operation::TYPE_REFERENCE: {
				//do nothing
			} break;

		}
	}
}

void UndoRedo::redo() {

	ERR_FAIL_COND(action_level>0);

	if ((current_action+1)>=actions.size())
		return; //nothing to redo
	current_action++;

	_process_operation_list(actions[current_action].do_ops.front());
	version++;
}

void UndoRedo::undo() {

	ERR_FAIL_COND(action_level>0);
	if (current_action<0)
		return; //nothing to redo
	_process_operation_list(actions[current_action].undo_ops.front());
	current_action--;
}

void UndoRedo::clear_history() {

	ERR_FAIL_COND(action_level>0);
	_discard_redo();

	while(actions.size())
		_pop_history_tail();

	version++;
}

String UndoRedo::get_current_action_name() const {

	ERR_FAIL_COND_V(action_level>0,"");
	if (current_action<0)
		return ""; //nothing to redo
	return actions[current_action].name;
}

void UndoRedo::set_max_steps(int p_max_steps) {

	max_steps=p_max_steps;
}

int UndoRedo::get_max_steps() const {

	return max_steps;
}

uint64_t UndoRedo::get_version() const {

	return version;
}

void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback,void* p_ud) {

	callback=p_callback;
	callback_ud=p_ud;
}

UndoRedo::UndoRedo() {

	version=0;
	action_level=0;
	current_action=-1;
	max_steps=-1;
	merging=true;
	callback=NULL;
	callback_ud=NULL;
}

UndoRedo::~UndoRedo() {

	clear_history();
}
<|endoftext|>


<commit_before>#ifdef STAN_OPENCL
#include <stan/math/opencl/rev.hpp>
#include <stan/math.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/opencl/util.hpp>
#include <vector>

TEST(ProbDistributionsGumbelCdf, error_checking) {
  int N = 3;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  Eigen::VectorXd y_size(N - 1);
  y_size << 0.3, 0.8;
  Eigen::VectorXd y_value(N);
  y_value << 0.3, NAN, 0.5;

  Eigen::VectorXd mu(N);
  mu << 0.3, 0.8, 1.0;
  Eigen::VectorXd mu_size(N - 1);
  mu_size << 0.3, 0.8;
  Eigen::VectorXd mu_value(N);
  mu_value << 0.3, -INFINITY, 0.5;

  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;
  Eigen::VectorXd sigma_size(N - 1);
  sigma_size << 0.3, 0.8;
  Eigen::VectorXd sigma_value(N);
  sigma_value << 0.3, 0, 0.5;

  stan::math::matrix_cl<double> y_cl(y);
  stan::math::matrix_cl<double> y_size_cl(y_size);
  stan::math::matrix_cl<double> y_value_cl(y_value);
  stan::math::matrix_cl<double> mu_cl(mu);
  stan::math::matrix_cl<double> mu_size_cl(mu_size);
  stan::math::matrix_cl<double> mu_value_cl(mu_value);
  stan::math::matrix_cl<double> sigma_cl(sigma);
  stan::math::matrix_cl<double> sigma_size_cl(sigma_size);
  stan::math::matrix_cl<double> sigma_value_cl(sigma_value);

  EXPECT_NO_THROW(stan::math::gumbel_cdf(y_cl, mu_cl, sigma_cl));

  EXPECT_THROW(stan::math::gumbel_cdf(y_size_cl, mu_cl, sigma_cl),
               std::invalid_argument);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_size_cl, sigma_cl),
               std::invalid_argument);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_cl, sigma_size_cl),
               std::invalid_argument);

  EXPECT_THROW(stan::math::gumbel_cdf(y_value_cl, mu_cl, sigma_cl),
               std::domain_error);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_value_cl, sigma_cl),
               std::domain_error);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_cl, sigma_value_cl),
               std::domain_error);
}

auto gumbel_cdf_functor = [](const auto& y, const auto& mu, const auto& sigma) {
  return stan::math::gumbel_cdf(y, mu, sigma);
};

TEST(ProbDistributionsGumbelCdf, opencl_matches_cpu_small) {
  int N = 3;
  int M = 2;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  Eigen::VectorXd mu(N);
  mu << 0.3, 0.8, 1.0;
  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;

  stan::math::test::compare_cpu_opencl_prim_rev(gumbel_cdf_functor, y, mu,
                                                sigma);
  stan::math::test::compare_cpu_opencl_prim_rev(
      gumbel_cdf_functor, y.transpose().eval(), mu.transpose().eval(),
      sigma.transpose().eval());
}

TEST(ProbDistributionsGumbelCdf, opencl_broadcast_y) {
  int N = 3;

  double y_scal = 12.3;
  Eigen::VectorXd mu(N);
  mu << 0.5, 1.2, 1.0;
  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;

  stan::math::test::test_opencl_broadcasting_prim_rev<0>(gumbel_cdf_functor,
                                                         y_scal, mu, sigma);
  stan::math::test::test_opencl_broadcasting_prim_rev<0>(
      gumbel_cdf_functor, y_scal, mu.transpose().eval(), sigma);
}

TEST(ProbDistributionsGumbelCdf, opencl_broadcast_mu) {
  int N = 3;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  double mu_scal = 12.3;
  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;

  stan::math::test::test_opencl_broadcasting_prim_rev<1>(gumbel_cdf_functor, y,
                                                         mu_scal, sigma);
  stan::math::test::test_opencl_broadcasting_prim_rev<1>(
      gumbel_cdf_functor, y.transpose().eval(), mu_scal, sigma);
}

TEST(ProbDistributionsGumbelCdf, opencl_broadcast_sigma) {
  int N = 3;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  Eigen::VectorXd mu(N);
  mu << 0.3, 0.8, 1.0;
  double sigma_scal = 12.3;

  stan::math::test::test_opencl_broadcasting_prim_rev<2>(gumbel_cdf_functor, y,
                                                         mu, sigma_scal);
  stan::math::test::test_opencl_broadcasting_prim_rev<2>(
      gumbel_cdf_functor, y.transpose().eval(), mu, sigma_scal);
}

TEST(ProbDistributionsGumbelCdf, opencl_matches_cpu_big) {
  int N = 153;

  Eigen::Matrix<double, Eigen::Dynamic, 1> y
      = Eigen::Array<double, Eigen::Dynamic, 1>::Random(N, 1).abs();
  Eigen::Matrix<double, Eigen::Dynamic, 1> mu
      = Eigen::Array<double, Eigen::Dynamic, 1>::Random(N, 1).abs();
  Eigen::Matrix<double, Eigen::Dynamic, 1> sigma
      = Eigen::Array<double, Eigen::Dynamic, 1>::Random(N, 1).abs();

  stan::math::test::compare_cpu_opencl_prim_rev(gumbel_cdf_functor, y, mu,
                                                sigma);
  stan::math::test::compare_cpu_opencl_prim_rev(
      gumbel_cdf_functor, y.transpose().eval(), mu.transpose().eval(),
      sigma.transpose().eval());
}
#endif
<commit_msg>adjust test values<commit_after>#ifdef STAN_OPENCL
#include <stan/math/opencl/rev.hpp>
#include <stan/math.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/opencl/util.hpp>
#include <vector>

TEST(ProbDistributionsGumbelCdf, error_checking) {
  int N = 3;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  Eigen::VectorXd y_size(N - 1);
  y_size << 0.3, 0.8;
  Eigen::VectorXd y_value(N);
  y_value << 0.3, NAN, 0.5;

  Eigen::VectorXd mu(N);
  mu << 0.3, 0.8, 1.0;
  Eigen::VectorXd mu_size(N - 1);
  mu_size << 0.3, 0.8;
  Eigen::VectorXd mu_value(N);
  mu_value << 0.3, -INFINITY, 0.5;

  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;
  Eigen::VectorXd sigma_size(N - 1);
  sigma_size << 0.3, 0.8;
  Eigen::VectorXd sigma_value(N);
  sigma_value << 0.3, 0, 0.5;

  stan::math::matrix_cl<double> y_cl(y);
  stan::math::matrix_cl<double> y_size_cl(y_size);
  stan::math::matrix_cl<double> y_value_cl(y_value);
  stan::math::matrix_cl<double> mu_cl(mu);
  stan::math::matrix_cl<double> mu_size_cl(mu_size);
  stan::math::matrix_cl<double> mu_value_cl(mu_value);
  stan::math::matrix_cl<double> sigma_cl(sigma);
  stan::math::matrix_cl<double> sigma_size_cl(sigma_size);
  stan::math::matrix_cl<double> sigma_value_cl(sigma_value);

  EXPECT_NO_THROW(stan::math::gumbel_cdf(y_cl, mu_cl, sigma_cl));

  EXPECT_THROW(stan::math::gumbel_cdf(y_size_cl, mu_cl, sigma_cl),
               std::invalid_argument);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_size_cl, sigma_cl),
               std::invalid_argument);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_cl, sigma_size_cl),
               std::invalid_argument);

  EXPECT_THROW(stan::math::gumbel_cdf(y_value_cl, mu_cl, sigma_cl),
               std::domain_error);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_value_cl, sigma_cl),
               std::domain_error);
  EXPECT_THROW(stan::math::gumbel_cdf(y_cl, mu_cl, sigma_value_cl),
               std::domain_error);
}

auto gumbel_cdf_functor = [](const auto& y, const auto& mu, const auto& sigma) {
  return stan::math::gumbel_cdf(y, mu, sigma);
};

TEST(ProbDistributionsGumbelCdf, opencl_matches_cpu_small) {
  int N = 3;
  int M = 2;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  Eigen::VectorXd mu(N);
  mu << 0.3, 0.8, 1.0;
  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;

  stan::math::test::compare_cpu_opencl_prim_rev(gumbel_cdf_functor, y, mu,
                                                sigma);
  stan::math::test::compare_cpu_opencl_prim_rev(
      gumbel_cdf_functor, y.transpose().eval(), mu.transpose().eval(),
      sigma.transpose().eval());
}

TEST(ProbDistributionsGumbelCdf, opencl_broadcast_y) {
  int N = 3;

  double y_scal = 12.3;
  Eigen::VectorXd mu(N);
  mu << 0.5, 1.2, 1.0;
  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;

  stan::math::test::test_opencl_broadcasting_prim_rev<0>(gumbel_cdf_functor,
                                                         y_scal, mu, sigma);
  stan::math::test::test_opencl_broadcasting_prim_rev<0>(
      gumbel_cdf_functor, y_scal, mu.transpose().eval(), sigma);
}

TEST(ProbDistributionsGumbelCdf, opencl_broadcast_mu) {
  int N = 3;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  double mu_scal = 12.3;
  Eigen::VectorXd sigma(N);
  sigma << 0.3, 0.8, 1.0;

  stan::math::test::test_opencl_broadcasting_prim_rev<1>(gumbel_cdf_functor, y,
                                                         mu_scal, sigma);
  stan::math::test::test_opencl_broadcasting_prim_rev<1>(
      gumbel_cdf_functor, y.transpose().eval(), mu_scal, sigma);
}

TEST(ProbDistributionsGumbelCdf, opencl_broadcast_sigma) {
  int N = 3;

  Eigen::VectorXd y(N);
  y << 0.3, 0.8, 1.0;
  Eigen::VectorXd mu(N);
  mu << 0.3, 0.8, 1.0;
  double sigma_scal = 12.3;

  stan::math::test::test_opencl_broadcasting_prim_rev<2>(gumbel_cdf_functor, y,
                                                         mu, sigma_scal);
  stan::math::test::test_opencl_broadcasting_prim_rev<2>(
      gumbel_cdf_functor, y.transpose().eval(), mu, sigma_scal);
}

TEST(ProbDistributionsGumbelCdf, opencl_matches_cpu_big) {
  int N = 153;

  Eigen::Matrix<double, Eigen::Dynamic, 1> y
      = Eigen::Array<double, Eigen::Dynamic, 1>::Random(N, 1).abs();
  Eigen::Matrix<double, Eigen::Dynamic, 1> mu
      = Eigen::Array<double, Eigen::Dynamic, 1>::Random(N, 1).abs();
  Eigen::Matrix<double, Eigen::Dynamic, 1> sigma
      = Eigen::Array<double, Eigen::Dynamic, 1>::Random(N, 1).abs() + 0.1;

  stan::math::test::compare_cpu_opencl_prim_rev(gumbel_cdf_functor, y, mu,
                                                sigma);
  stan::math::test::compare_cpu_opencl_prim_rev(
      gumbel_cdf_functor, y.transpose().eval(), mu.transpose().eval(),
      sigma.transpose().eval());
}
#endif
<|endoftext|>


<commit_before>/*
  Firmata.cpp - Firmata library
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.

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

  See file LICENSE.txt for further informations on licensing terms.
*/

//******************************************************************************
//* Includes
//******************************************************************************

#include "Firmata_mapper.h"
#include "HardwareSerial.h"

extern "C" {
#include <string.h>
#include <stdlib.h>
#include <iostream>
}

//******************************************************************************
//* Support Functions
//******************************************************************************

void FirmataClass::sendValueAsTwo7bitBytes(int value)
{
  FirmataSerial.write(value & B01111111); // LSB
  FirmataSerial.write(value >> 7 & B01111111); // MSB
}

void FirmataClass::startSysex(void)
{
  FirmataSerial.write(START_SYSEX);
}

void FirmataClass::endSysex(void)
{
  FirmataSerial.write(END_SYSEX);
}

//******************************************************************************
//* Constructors
//******************************************************************************

FirmataClass::FirmataClass(Stream &s) : FirmataSerial(s)
{
  firmwareVersionCount = 0;
  systemReset();
}

//******************************************************************************
//* Public Methods
//******************************************************************************

/* begin method for overriding default serial bitrate */
void FirmataClass::begin(void)
{
  begin(57600);
}

/* begin method for overriding default serial bitrate */
void FirmataClass::begin(long speed)
{
  Serial.begin(speed);
  FirmataSerial = Serial;
  blinkVersion();
  printVersion();
  printFirmwareVersion();
}

void FirmataClass::begin(Stream &s)
{
  FirmataSerial = s;
  systemReset();
  printVersion();
  printFirmwareVersion();
}

// output the protocol version message to the serial port
void FirmataClass::printVersion(void) {
  FirmataSerial.write(REPORT_VERSION);
  FirmataSerial.write(FIRMATA_MAJOR_VERSION);
  FirmataSerial.write(FIRMATA_MINOR_VERSION);
}

void FirmataClass::blinkVersion(void)
{
  // flash the pin with the protocol version
  pinMode(VERSION_BLINK_PIN,OUTPUT);
  pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210);
  delay(250);
  pin13strobe(FIRMATA_MINOR_VERSION, 40, 210);
  delay(125);
}

void FirmataClass::printFirmwareVersion(void)
{
  byte i;

  if(firmwareVersionCount) { // make sure that the name has been set before reporting
    startSysex();
    FirmataSerial.write(REPORT_FIRMWARE);
    FirmataSerial.write(firmwareVersionVector[0]); // major version number
    FirmataSerial.write(firmwareVersionVector[1]); // minor version number
    for(i=2; i<firmwareVersionCount; ++i) {
      sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
    }
    endSysex();
  }
}

void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{
  const char *filename;
  char *extension;

  // parse out ".cpp" and "applet/" that comes from using __FILE__
  extension = strstr(name, ".cpp");
  filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
  // add two bytes for version numbers
  if(extension && filename) {
    firmwareVersionCount = extension - filename + 2;
  } else {
    firmwareVersionCount = strlen(name) + 2;
    filename = name;
  }
  firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
  firmwareVersionVector[firmwareVersionCount] = 0;
  firmwareVersionVector[0] = major;
  firmwareVersionVector[1] = minor;
  strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
  // alas, no snprintf on Arduino
  //    snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
  //             (char)major, (char)minor, firmwareVersionVector);
}

//------------------------------------------------------------------------------
// Serial Receive Handling

int FirmataClass::available(void)
{
  return FirmataSerial.available();
}

void FirmataClass::processSysexMessage(void)
{
  switch(storedInputData[0]) { //first byte in buffer is command
  case REPORT_FIRMWARE:
    printFirmwareVersion();
    break;
  case STRING_DATA:
    if(currentStringCallback) {
      byte bufferLength = (sysexBytesRead - 1) / 2;
      char *buffer = (char*)malloc(bufferLength * sizeof(char));
      byte i = 1;
      byte j = 0;
      while(j < bufferLength) {
        buffer[j] = (char)storedInputData[i];
        i++;
        buffer[j] += (char)(storedInputData[i] << 7);
        i++;
        j++;
      }
      (*currentStringCallback)(buffer);
    }
    break;
  default:
    if(currentSysexCallback){
      /*FirmataSerial.print("name dans sysex : ");
      for (int i = 0; i< 32; i++){
	FirmataSerial.print(storedInputData[i]);
	}*/

      (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
    }
  }
}

void FirmataClass::processInput(void)
{
  int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data
  int command;

  // TODO make sure it handles -1 properly

  if (parsingSysex) {

    if(inputData == END_SYSEX) {
      //stop sysex byte
      parsingSysex = false;
      //fire off handler function
      processSysexMessage();
    } else {
      //normal data byte - add to buffer
      storedInputData[sysexBytesRead] = inputData;
      sysexBytesRead++;
    }
  }/* else if (inputData == EEPROM_WRITING){
    if(currentEEPROMWritingCallback){
      (*currentEEPROMWritingCallback)(multiByteChannel,storedInputData[0]);
    }
    }*/
 else if( (waitForData > 0) && (inputData < 128) ) {
    waitForData--;
    storedInputData[waitForData] = inputData;
    if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
      switch(executeMultiByteCommand) {
      case ANALOG_MESSAGE:
        if(currentAnalogCallback) {
          (*currentAnalogCallback)(multiByteChannel,
                                   (storedInputData[0] << 7)
                                   + storedInputData[1]);
        }
        break;
      case DIGITAL_MESSAGE:
        if(currentDigitalCallback) {
          (*currentDigitalCallback)(multiByteChannel,
                                    (storedInputData[0] << 7)
                                    + storedInputData[1]);
        }
        break;
      case SET_PIN_PROP:
	byte name[29];
	for (int i=0; i<28 ; i++)
	  name[i] = storedInputData[28-i];
        if(currentPinPropCallback)
          (*currentPinPropCallback)(storedInputData[30], storedInputData[29], name);
        break;
      case REPORT_ANALOG:
        if(currentReportAnalogCallback)
          (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
        break;
      case REPORT_DIGITAL:
        if(currentReportDigitalCallback)
          (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
        break;
      case EEPROM_WRITING:
	if(currentEEPROMWritingCallback){
          (*currentEEPROMWritingCallback)(multiByteChannel,storedInputData[0]);
	}
	  break;
      }
      executeMultiByteCommand = 0;
    }
  } else {
    // remove channel info from command byte if less than 0xF0
    if(inputData < 0x07) {
      command = inputData & 0xF0;
      multiByteChannel = inputData & 0x0F;
    } else {
      command = inputData;
      // commands in the 0xF* range don't use channel data
    }
    switch (command) {
    case ANALOG_MESSAGE:
    case DIGITAL_MESSAGE:
      waitForData = 2; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case SET_PIN_PROP:
      waitForData = 31; //2;//35; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case REPORT_ANALOG:
    case REPORT_DIGITAL:
      waitForData = 1; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case EEPROM_WRITING :
      waitForData = 2;
      executeMultiByteCommand = command;
      break;
    case START_SYSEX:
      parsingSysex = true;
      sysexBytesRead = 0;
      break;
    case SYSTEM_RESET:
      systemReset();
      break;
    case REPORT_VERSION:
      Firmata.printVersion();
      break;
    }
  }
}

//------------------------------------------------------------------------------
// Serial Send Handling

// send an analog message
void FirmataClass::sendAnalog(byte pin, int value)
{
  // pin can only be 0-15, so chop higher bits
  FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF));
  sendValueAsTwo7bitBytes(value);
}

// send a single digital pin in a digital message
void FirmataClass::sendDigital(byte pin, int value)
{
  /* TODO add single pin digital messages to the protocol, this needs to
   * track the last digital data sent so that it can be sure to change just
   * one bit in the packet.  This is complicated by the fact that the
   * numbering of the pins will probably differ on Arduino, Wiring, and
   * other boards.  The DIGITAL_MESSAGE sends 14 bits at a time, but it is
   * probably easier to send 8 bit ports for any board with more than 14
   * digital pins.
   */

  // TODO: the digital message should not be sent on the serial port every
  // time sendDigital() is called.  Instead, it should add it to an int
  // which will be sent on a schedule.  If a pin changes more than once
  // before the digital message is sent on the serial port, it should send a
  // digital message for each change.

  //    if(value == 0)
  //        sendDigitalPortPair();
}

// send 14-bits in a single digital message (protocol v1)
// send an 8-bit port in a single digital message (protocol v2)
void FirmataClass::sendDigitalPort(byte portNumber, int portData)
{
  FirmataSerial.write(DIGITAL_MESSAGE | (portNumber & 0xF));
  FirmataSerial.write((byte)portData % 128); // Tx bits 0-6
  FirmataSerial.write(portData >> 7);  // Tx bits 7-13
}

void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{
  byte i;
  startSysex();
  FirmataSerial.write(command);
  for(i=0; i<bytec; i++) {
    sendValueAsTwo7bitBytes(bytev[i]);
  }
  endSysex();
}

void FirmataClass::sendString(byte command, const char* string)
{
  sendSysex(command, strlen(string), (byte *)string);
}

// send a string as the protocol string type
void FirmataClass::sendString(const char* string)
{
  sendString(STRING_DATA, string);
}

// Internal Actions/////////////////////////////////////////////////////////////

// generic callbacks
void FirmataClass::attach(byte command, callbackFunction newFunction)
{
  Serial.print("attach");
  switch(command) {
  case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
  case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
  case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
  case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
    // case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
  case EEPROM_WRITING: currentEEPROMWritingCallback = newFunction; break;
  }
}

void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
  }
}

void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{
  switch(command) {
  case STRING_DATA: currentStringCallback = newFunction; break;
  }
}

void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{
  currentSysexCallback = newFunction;
}

void FirmataClass::attach(byte command, propCallbackFunction newFunction)
{
  currentPinPropCallback = newFunction;
}

/*void FirmataClass::attach(byte command, EEPROMWritingCallbackFunction newFunction)
{
  currentEEPROMWritingCallback = newFunction;
}*/

void FirmataClass::detach(byte command)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
  case STRING_DATA: currentStringCallback = NULL; break;
  case START_SYSEX: currentSysexCallback = NULL; break;
  default:
    attach(command, (callbackFunction)NULL);
  }
}

// sysex callbacks
/*
 * this is too complicated for analogReceive, but maybe for Sysex?
 void FirmataClass::attachSysex(sysexFunction newFunction)
 {
 byte i;
 byte tmpCount = analogReceiveFunctionCount;
 analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
 analogReceiveFunctionCount++;
 analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
 for(i = 0; i < tmpCount; i++) {
 analogReceiveFunctionArray[i] = tmpArray[i];
 }
 analogReceiveFunctionArray[tmpCount] = newFunction;
 free(tmpArray);
 }
*/

//******************************************************************************
//* Private Methods
//******************************************************************************

// resets the system state upon a SYSTEM_RESET message from the host software
void FirmataClass::systemReset(void)
{
  byte i;

  waitForData = 0; // this flag says the next serial input will be data
  executeMultiByteCommand = 0; // execute this after getting multi-byte data
  multiByteChannel = 0; // channel data for multiByteCommands

  for(i=0; i<MAX_DATA_BYTES; i++) {
    storedInputData[i] = 0;
  }

  parsingSysex = false;
  sysexBytesRead = 0;

  if(currentSystemResetCallback)
    (*currentSystemResetCallback)();

  //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
}

// =============================================================================
// used for flashing the pin for the version number
void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{
  byte i;
  pinMode(VERSION_BLINK_PIN, OUTPUT);
  for(i=0; i<count; i++) {
    delay(offInterval);
    digitalWrite(VERSION_BLINK_PIN, HIGH);
    delay(onInterval);
    digitalWrite(VERSION_BLINK_PIN, LOW);
  }
}

// make one instance for the user to use
FirmataClass Firmata(Serial);

<commit_msg>EEPROM protocol in progress (add of the load button)<commit_after>/*
  Firmata.cpp - Firmata library
  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.

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

  See file LICENSE.txt for further informations on licensing terms.
*/

//******************************************************************************
//* Includes
//******************************************************************************

#include "Firmata_mapper.h"
#include "HardwareSerial.h"

extern "C" {
#include <string.h>
#include <stdlib.h>
#include <iostream>
}

//******************************************************************************
//* Support Functions
//******************************************************************************

void FirmataClass::sendValueAsTwo7bitBytes(int value)
{
  FirmataSerial.write(value & B01111111); // LSB
  FirmataSerial.write(value >> 7 & B01111111); // MSB
}

void FirmataClass::startSysex(void)
{
  FirmataSerial.write(START_SYSEX);
}

void FirmataClass::endSysex(void)
{
  FirmataSerial.write(END_SYSEX);
}

//******************************************************************************
//* Constructors
//******************************************************************************

FirmataClass::FirmataClass(Stream &s) : FirmataSerial(s)
{
  firmwareVersionCount = 0;
  systemReset();
}

//******************************************************************************
//* Public Methods
//******************************************************************************

/* begin method for overriding default serial bitrate */
void FirmataClass::begin(void)
{
  begin(57600);
}

/* begin method for overriding default serial bitrate */
void FirmataClass::begin(long speed)
{
  Serial.begin(speed);
  FirmataSerial = Serial;
  blinkVersion();
  printVersion();
  printFirmwareVersion();
}

void FirmataClass::begin(Stream &s)
{
  FirmataSerial = s;
  systemReset();
  printVersion();
  printFirmwareVersion();
}

// output the protocol version message to the serial port
void FirmataClass::printVersion(void) {
  FirmataSerial.write(REPORT_VERSION);
  FirmataSerial.write(FIRMATA_MAJOR_VERSION);
  FirmataSerial.write(FIRMATA_MINOR_VERSION);
}

void FirmataClass::blinkVersion(void)
{
  // flash the pin with the protocol version
  pinMode(VERSION_BLINK_PIN,OUTPUT);
  pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210);
  delay(250);
  pin13strobe(FIRMATA_MINOR_VERSION, 40, 210);
  delay(125);
}

void FirmataClass::printFirmwareVersion(void)
{
  byte i;

  if(firmwareVersionCount) { // make sure that the name has been set before reporting
    startSysex();
    FirmataSerial.write(REPORT_FIRMWARE);
    FirmataSerial.write(firmwareVersionVector[0]); // major version number
    FirmataSerial.write(firmwareVersionVector[1]); // minor version number
    for(i=2; i<firmwareVersionCount; ++i) {
      sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
    }
    endSysex();
  }
}

void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{
  const char *filename;
  char *extension;

  // parse out ".cpp" and "applet/" that comes from using __FILE__
  extension = strstr(name, ".cpp");
  filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
  // add two bytes for version numbers
  if(extension && filename) {
    firmwareVersionCount = extension - filename + 2;
  } else {
    firmwareVersionCount = strlen(name) + 2;
    filename = name;
  }
  firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
  firmwareVersionVector[firmwareVersionCount] = 0;
  firmwareVersionVector[0] = major;
  firmwareVersionVector[1] = minor;
  strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
  // alas, no snprintf on Arduino
  //    snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
  //             (char)major, (char)minor, firmwareVersionVector);
}

//------------------------------------------------------------------------------
// Serial Receive Handling

int FirmataClass::available(void)
{
  return FirmataSerial.available();
}

void FirmataClass::processSysexMessage(void)
{
  switch(storedInputData[0]) { //first byte in buffer is command
  case REPORT_FIRMWARE:
    printFirmwareVersion();
    break;
  case STRING_DATA:
    if(currentStringCallback) {
      byte bufferLength = (sysexBytesRead - 1) / 2;
      char *buffer = (char*)malloc(bufferLength * sizeof(char));
      byte i = 1;
      byte j = 0;
      while(j < bufferLength) {
        buffer[j] = (char)storedInputData[i];
        i++;
        buffer[j] += (char)(storedInputData[i] << 7);
        i++;
        j++;
      }
      (*currentStringCallback)(buffer);
    }
    break;
  default:
    if(currentSysexCallback){
      /*FirmataSerial.print("name dans sysex : ");
      for (int i = 0; i< 32; i++){
	FirmataSerial.print(storedInputData[i]);
	}*/

      (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
    }
  }
}

void FirmataClass::processInput(void)
{
  int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data
  int command;

  // TODO make sure it handles -1 properly

  if (parsingSysex) {

    if(inputData == END_SYSEX) {
      //stop sysex byte
      parsingSysex = false;
      //fire off handler function
      processSysexMessage();
    } else {
      //normal data byte - add to buffer
      storedInputData[sysexBytesRead] = inputData;
      sysexBytesRead++;
    }
  }/* else if (inputData == EEPROM_WRITING){
    if(currentEEPROMWritingCallback){
      (*currentEEPROMWritingCallback)(multiByteChannel,storedInputData[0]);
    }
    }*/
 else if( (waitForData > 0) && (inputData < 128) ) {
    waitForData--;
    storedInputData[waitForData] = inputData;
    if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
      switch(executeMultiByteCommand) {
      case ANALOG_MESSAGE:
        if(currentAnalogCallback) {
          (*currentAnalogCallback)(multiByteChannel,
                                   (storedInputData[0] << 7)
                                   + storedInputData[1]);
        }
        break;
      case DIGITAL_MESSAGE:
        if(currentDigitalCallback) {
          (*currentDigitalCallback)(multiByteChannel,
                                    (storedInputData[0] << 7)
                                    + storedInputData[1]);
        }
        break;
      case SET_PIN_PROP:
	byte name[29];
	for (int i=0; i<28 ; i++)
	  name[i] = storedInputData[28-i];
        if(currentPinPropCallback)
          (*currentPinPropCallback)(storedInputData[30], storedInputData[29], name);
        break;
      case REPORT_ANALOG:
        if(currentReportAnalogCallback)
          (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
        break;
      case REPORT_DIGITAL:
        if(currentReportDigitalCallback)
          (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
        break;
      case EEPROM_WRITING:
	if(currentEEPROMWritingCallback){
          (*currentEEPROMWritingCallback)(multiByteChannel,storedInputData[0]);
	}
	  break;
      }
      executeMultiByteCommand = 0;
    }
  } else {
    // remove channel info from command byte if less than 0xF0
    if(inputData < 0x07) {
      command = inputData & 0xF0;
      multiByteChannel = inputData & 0x0F;
    } else {
      command = inputData;
      // commands in the 0xF* range don't use channel data
    }
    switch (command) {
    case ANALOG_MESSAGE:
    case DIGITAL_MESSAGE:
      waitForData = 2; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case SET_PIN_PROP:
      waitForData = 31; //2;//35; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case REPORT_ANALOG:
    case REPORT_DIGITAL:
      waitForData = 1; // two data bytes needed
      executeMultiByteCommand = command;
      break;
    case EEPROM_WRITING :
      waitForData = 1;
      executeMultiByteCommand = command;
      multiByteChannel = command;
      break;
    case START_SYSEX:
      parsingSysex = true;
      sysexBytesRead = 0;
      break;
    case SYSTEM_RESET:
      systemReset();
      break;
    case REPORT_VERSION:
      Firmata.printVersion();
      break;
    }
  }
}

//------------------------------------------------------------------------------
// Serial Send Handling

// send an analog message
void FirmataClass::sendAnalog(byte pin, int value)
{
  // pin can only be 0-15, so chop higher bits
  FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF));
  sendValueAsTwo7bitBytes(value);
}

// send a single digital pin in a digital message
void FirmataClass::sendDigital(byte pin, int value)
{
  /* TODO add single pin digital messages to the protocol, this needs to
   * track the last digital data sent so that it can be sure to change just
   * one bit in the packet.  This is complicated by the fact that the
   * numbering of the pins will probably differ on Arduino, Wiring, and
   * other boards.  The DIGITAL_MESSAGE sends 14 bits at a time, but it is
   * probably easier to send 8 bit ports for any board with more than 14
   * digital pins.
   */

  // TODO: the digital message should not be sent on the serial port every
  // time sendDigital() is called.  Instead, it should add it to an int
  // which will be sent on a schedule.  If a pin changes more than once
  // before the digital message is sent on the serial port, it should send a
  // digital message for each change.

  //    if(value == 0)
  //        sendDigitalPortPair();
}

// send 14-bits in a single digital message (protocol v1)
// send an 8-bit port in a single digital message (protocol v2)
void FirmataClass::sendDigitalPort(byte portNumber, int portData)
{
  FirmataSerial.write(DIGITAL_MESSAGE | (portNumber & 0xF));
  FirmataSerial.write((byte)portData % 128); // Tx bits 0-6
  FirmataSerial.write(portData >> 7);  // Tx bits 7-13
}

void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{
  byte i;
  startSysex();
  FirmataSerial.write(command);
  for(i=0; i<bytec; i++) {
    sendValueAsTwo7bitBytes(bytev[i]);
    //Serial.print(i);
    //Serial.print(" : ");
    //Serial.print(bytev[i]);
    //Serial.print(", ");
  }
  endSysex();
}

void FirmataClass::sendString(byte command, const char* string)
{
  sendSysex(command, strlen(string), (byte *)string);
}

// send a string as the protocol string type
void FirmataClass::sendString(const char* string)
{
  sendString(STRING_DATA, string);
}

// Internal Actions/////////////////////////////////////////////////////////////

// generic callbacks
void FirmataClass::attach(byte command, callbackFunction newFunction)
{
  Serial.print("attach");
  switch(command) {
  case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
  case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
  case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
  case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
    // case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
  case EEPROM_WRITING: currentEEPROMWritingCallback = newFunction; break;
  }
}

void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
  }
}

void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{
  switch(command) {
  case STRING_DATA: currentStringCallback = newFunction; break;
  }
}

void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{
  currentSysexCallback = newFunction;
}

void FirmataClass::attach(byte command, propCallbackFunction newFunction)
{
  currentPinPropCallback = newFunction;
}

/*void FirmataClass::attach(byte command, EEPROMWritingCallbackFunction newFunction)
{
  currentEEPROMWritingCallback = newFunction;
}*/

void FirmataClass::detach(byte command)
{
  switch(command) {
  case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
  case STRING_DATA: currentStringCallback = NULL; break;
  case START_SYSEX: currentSysexCallback = NULL; break;
  default:
    attach(command, (callbackFunction)NULL);
  }
}

// sysex callbacks
/*
 * this is too complicated for analogReceive, but maybe for Sysex?
 void FirmataClass::attachSysex(sysexFunction newFunction)
 {
 byte i;
 byte tmpCount = analogReceiveFunctionCount;
 analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
 analogReceiveFunctionCount++;
 analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
 for(i = 0; i < tmpCount; i++) {
 analogReceiveFunctionArray[i] = tmpArray[i];
 }
 analogReceiveFunctionArray[tmpCount] = newFunction;
 free(tmpArray);
 }
*/

//******************************************************************************
//* Private Methods
//******************************************************************************

// resets the system state upon a SYSTEM_RESET message from the host software
void FirmataClass::systemReset(void)
{
  byte i;

  waitForData = 0; // this flag says the next serial input will be data
  executeMultiByteCommand = 0; // execute this after getting multi-byte data
  multiByteChannel = 0; // channel data for multiByteCommands

  for(i=0; i<MAX_DATA_BYTES; i++) {
    storedInputData[i] = 0;
  }

  parsingSysex = false;
  sysexBytesRead = 0;

  if(currentSystemResetCallback)
    (*currentSystemResetCallback)();

  //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
}

// =============================================================================
// used for flashing the pin for the version number
void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{
  byte i;
  pinMode(VERSION_BLINK_PIN, OUTPUT);
  for(i=0; i<count; i++) {
    delay(offInterval);
    digitalWrite(VERSION_BLINK_PIN, HIGH);
    delay(onInterval);
    digitalWrite(VERSION_BLINK_PIN, LOW);
  }
}

// make one instance for the user to use
FirmataClass Firmata(Serial);

<|endoftext|>


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

#include "../../src/endpoint.hpp"
#include "../../src/roles/client.hpp"

#include <iostream>

typedef websocketpp::endpoint<websocketpp::role::client,websocketpp::socket::plain> plain_endpoint_type;
typedef plain_endpoint_type::handler_ptr plain_handler_ptr;
typedef plain_endpoint_type::connection_ptr connection_ptr;

class echo_client_handler : public plain_endpoint_type::handler {
public:
	typedef echo_client_handler type;
	typedef plain_endpoint_type::connection_ptr connection_ptr;

	void on_open(connection_ptr connection) {
		agent = connection->get_response_header("Server");
		std::cout << "Testing agent " << agent << std::endl;

		// needs more C++11 intializer lists =(
		test_9_1_X_sizes[0] = 65536;
		test_9_1_X_sizes[1] = 262144;
		test_9_1_X_sizes[2] = 262144;
		test_9_1_X_sizes[3] = 4194304;
		test_9_1_X_sizes[4] = 8388608;
		test_9_1_X_sizes[5] = 16777216;

		test = 1;

		start_9_1_X(test);
		connection->send(data,true);
	}

	void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) {
		end_time = boost::posix_time::microsec_clock::local_time();

		boost::posix_time::time_period len(start_time,end_time);

		if (msg->get_payload() == data) {
			std::cout << " passes in " << len.length() << std::endl;
		} else {
			std::cout << " fails in " << len.length() << std::endl;
		}

		connection->recycle(msg);

		if (test == 6) {
			std::cout << "Done" << std::endl;
			connection->close(websocketpp::close::status::NORMAL, "");
		} else {
			test++;
			start_9_1_X(test);
			connection->send(data,true);
		}
	}

	void http(connection_ptr connection) {
		//connection->set_body("HTTP Response!!");
	}

	void on_fail(connection_ptr connection) {
		std::cout << "connection failed" << std::endl;
	}

	void start_9_1_X(int subtest) {
		std::cout << "Test 9.2." << subtest << " ";

		data.reserve(test_9_1_X_sizes[subtest-1]);
		data.assign(test_9_1_X_sizes[subtest-1],'*');
		start_time = boost::posix_time::microsec_clock::local_time();
	}

	size_t	test_9_1_X_sizes[6];
	int			test;
	std::string agent;
	std::string data;
	boost::posix_time::ptime start_time;
	boost::posix_time::ptime end_time;
};

int main(int argc, char* argv[]) {
	std::string uri;

	/*if (argc != 2) {
		std::cout << "Usage: `echo_client test_url`" << std::endl;
	} else {
		uri = argv[1];
	}*/

	try {
		plain_handler_ptr handler(new echo_client_handler());
        connection_ptr connection;
		plain_endpoint_type endpoint(handler);

		endpoint.alog().unset_level(websocketpp::log::alevel::ALL);

		endpoint.elog().unset_level(websocketpp::log::elevel::ALL);

		connection = endpoint.connect("ws://localhost:9000/");

        endpoint.run();

		std::cout << "done" << std::endl;

	} catch (std::exception& e) {
		std::cerr << "Exception: " << e.what() << std::endl;
	}

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

#include "../../src/endpoint.hpp"
#include "../../src/roles/client.hpp"

#include <iostream>

typedef websocketpp::endpoint<websocketpp::role::client,websocketpp::socket::plain> plain_endpoint_type;
typedef plain_endpoint_type::handler_ptr plain_handler_ptr;
typedef plain_endpoint_type::connection_ptr connection_ptr;

// base test case handler
class test_case_handler : public plain_endpoint_type::handler {
public:
	typedef test_case_handler type;
	typedef plain_endpoint_type::connection_ptr connection_ptr;

	virtual void end(connection_ptr connection) {
		// test is over, give control back to controlling handler
		boost::posix_time::time_period len(m_start_time,m_end_time);

		if (m_pass) {
			std::cout << " passes in " << len.length() << std::endl;
		} else {
			std::cout << " fails in " << len.length() << std::endl;
		}

		connection->close(websocketpp::close::status::NORMAL,"");
	}
protected:
	bool						m_pass;
	boost::posix_time::ptime	m_start_time;
	boost::posix_time::ptime	m_end_time;
};

// test class for 9.1.* and 9.2.*
class test_9_1_X : public test_case_handler {
public:
	test_9_1_X(int minor, int subtest) : m_minor(minor),m_subtest(subtest){
		// needs more C++11 intializer lists =(
		m_test_sizes[0] = 65536;
		m_test_sizes[1] = 262144;
		m_test_sizes[2] = 1048576;
		m_test_sizes[3] = 4194304;
		m_test_sizes[4] = 8388608;
		m_test_sizes[5] = 16777216;
	}

	void on_open(connection_ptr connection) {
		std::cout << "Test 9." << m_minor << "." << m_subtest;

		m_data.reserve(m_test_sizes[m_subtest-1]);

		if (m_minor == 1) {
			fill_utf8(connection,true);
			m_start_time = boost::posix_time::microsec_clock::local_time();
			connection->send(m_data,false);
		} else if (m_minor == 2) {
			fill_binary(connection,true);
			m_start_time = boost::posix_time::microsec_clock::local_time();
			connection->send(m_data,true);
		} else {
			std::cout << " has unknown definition." << std::endl;
		}
	}

	// Just does random ascii right now. True random UTF8 with multi-byte stuff
	// would probably be better
	void fill_utf8(connection_ptr connection,bool random = true) {
		if (random) {
			uint32_t data;
			for (int i = 0; i < m_test_sizes[m_subtest-1]; i++) {
				if (i%4 == 0) {
					data = uint32_t(connection->rand());
				}

				m_data.push_back(char(((reinterpret_cast<uint8_t*>(&data)[i%4])%95)+32));
			}
		} else {
			m_data.assign(m_test_sizes[m_subtest-1],'*');
		}
	}

	void fill_binary(connection_ptr connection, bool random = true) {
		if (random) {
			int32_t data;
			for (int i = 0; i < m_test_sizes[m_subtest-1]; i++) {
				if (i%4 == 0) {
					data = connection->rand();
				}

				m_data.push_back((reinterpret_cast<char*>(&data))[i%4]);
			}
		} else {
			m_data.assign(m_test_sizes[m_subtest-1],'*');
		}
	}

	void on_message(connection_ptr connection,websocketpp::message::data_ptr msg) {
		m_end_time = boost::posix_time::microsec_clock::local_time();

		// Check whether the echoed data matches exactly
		m_pass = (msg->get_payload() == m_data);

		connection->recycle(msg);
		this->end(connection);
	}
private:
	int			m_minor;
	int			m_subtest;
	size_t		m_test_sizes[6];
	std::string m_data;
};

int main(int argc, char* argv[]) {
	std::string uri;

	if (argc != 2) {
		uri = "ws://localhost:9002/";
	} else {
		uri = argv[1];
	}

	std::vector<plain_handler_ptr>	tests;

	for (int i = 1; i <= 2; i++) {
		for (int j = 1; j <= 6; j++) {
			tests.push_back(plain_handler_ptr(new test_9_1_X(i,j)));
		}
	}

	try {
		plain_endpoint_type endpoint(tests[0]);

		endpoint.alog().unset_level(websocketpp::log::alevel::ALL);
		endpoint.elog().unset_level(websocketpp::log::elevel::ALL);

		for (int i = 0; i < tests.size(); i++) {
			if (i > 0) {
				endpoint.reset();
				endpoint.set_handler(tests[i]);
			}

			endpoint.connect(uri);
			endpoint.run();
		}

		std::cout << "done" << std::endl;

	} catch (std::exception& e) {
		std::cerr << "Exception: " << e.what() << std::endl;
	}

	return 0;
}
<|endoftext|>