<commit_before>#pragma once

#include "value.hh"
#include "symbol-table.hh"

#include <map>

namespace nix {

MakeError(EvalError, Error)
MakeError(ParseError, Error)
MakeError(IncompleteParseError, ParseError)
MakeError(AssertionError, EvalError)
MakeError(ThrownError, AssertionError)
MakeError(Abort, EvalError)
MakeError(TypeError, EvalError)
MakeError(UndefinedVarError, Error)
MakeError(RestrictedPathError, Error)

/* Position objects. */

struct Pos
{
    Symbol file;
    unsigned int line, column;
    Pos() : line(0), column(0) { };
    Pos(const Symbol & file, unsigned int line, unsigned int column)
        : file(file), line(line), column(column) { };
    operator bool() const
    {
        return line != 0;
    }
    bool operator < (const Pos & p2) const
    {
        if (!line) return p2.line;
        if (!p2.line) return false;
        int d = ((string) file).compare((string) p2.file);
        if (d < 0) return true;
        if (d > 0) return false;
        if (line < p2.line) return true;
        if (line > p2.line) return false;
        return column < p2.column;
    }
};

extern Pos noPos;

std::ostream & operator << (std::ostream & str, const Pos & pos);

struct Env;
struct Value;
class EvalState;
struct StaticEnv;

/* An attribute path is a sequence of attribute names. */
struct AttrName
{
    Symbol symbol;
    Expr * expr;
    AttrName(const Symbol & s) : symbol(s) {};
    AttrName(Expr * e) : expr(e) {};
};

typedef std::vector<AttrName> AttrPath;

string showAttrPath(const AttrPath & attrPath);

/* Abstract syntax of Nix expressions. */

struct Expr
{
    virtual ~Expr() { };
    virtual void show(std::ostream & str);
    virtual void bindVars(const StaticEnv & env);
    virtual void eval(EvalState & state, Env & env, Value & v);
    virtual Value * maybeThunk(EvalState & state, Env & env);
    virtual void setName(Symbol & name);
};

std::ostream & operator << (std::ostream & str, Expr & e);

#define COMMON_METHODS \
    void show(std::ostream & str); \
    void eval(EvalState & state, Env & env, Value & v); \
    void bindVars(const StaticEnv & env);

struct ExprInt : Expr
{
    NixInt n;
    Value v;
    ExprInt(NixInt n) : n(n) { mkInt(v, n); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprFloat : Expr
{
    NixFloat nf;
    Value v;
    ExprFloat(NixFloat nf) : nf(nf) { mkFloat(v, nf); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprString : Expr
{
    Symbol s;
    Value v;
    ExprString(const Symbol & s) : s(s) { mkString(v, s); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

/* Temporary class used during parsing of indented strings. */
struct ExprIndStr : Expr
{
    string s;
    ExprIndStr(const string & s) : s(s) { };
};

struct ExprPath : Expr
{
    string s;
    Value v;
    ExprPath(const string & s) : s(s) { mkPathNoCopy(v, this->s.c_str()); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprVar : Expr
{
    Pos pos;
    Symbol name;

    /* Whether the variable comes from an environment (e.g. a rec, let
       or function argument) or from a "with". */
    bool fromWith;

    /* In the former case, the value is obtained by going `level'
       levels up from the current environment and getting the
       `displ'th value in that environment.  In the latter case, the
       value is obtained by getting the attribute named `name' from
       the set stored in the environment that is `level' levels up
       from the current one.*/
    unsigned int level;
    unsigned int displ;

    ExprVar(const Symbol & name) : name(name) { };
    ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprSelect : Expr
{
    Pos pos;
    Expr * e, * def;
    AttrPath attrPath;
    ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { };
    ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
    COMMON_METHODS
};

struct ExprOpHasAttr : Expr
{
    Expr * e;
    AttrPath attrPath;
    ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { };
    COMMON_METHODS
};

struct ExprAttrs : Expr
{
    bool recursive;
    struct AttrDef {
        bool inherited;
        Expr * e;
        Pos pos;
        unsigned int displ; // displacement
        AttrDef(Expr * e, const Pos & pos, bool inherited=false)
            : inherited(inherited), e(e), pos(pos) { };
        AttrDef() { };
    };
    typedef std::map<Symbol, AttrDef> AttrDefs;
    AttrDefs attrs;
    struct DynamicAttrDef {
        Expr * nameExpr, * valueExpr;
        Pos pos;
        DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const Pos & pos)
            : nameExpr(nameExpr), valueExpr(valueExpr), pos(pos) { };
    };
    typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
    DynamicAttrDefs dynamicAttrs;
    ExprAttrs() : recursive(false) { };
    COMMON_METHODS
};

struct ExprList : Expr
{
    std::vector<Expr *> elems;
    ExprList() { };
    COMMON_METHODS
};

struct Formal
{
    Symbol name;
    Expr * def;
    Formal(const Symbol & name, Expr * def) : name(name), def(def) { };
};

struct Formals
{
    typedef std::list<Formal> Formals_;
    Formals_ formals;
    std::set<Symbol> argNames; // used during parsing
    bool ellipsis;
};

struct ExprLambda : Expr
{
    Pos pos;
    Symbol name;
    Symbol arg;
    bool matchAttrs;
    Formals * formals;
    Expr * body;
    ExprLambda(const Pos & pos, const Symbol & arg, bool matchAttrs, Formals * formals, Expr * body)
        : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body)
    {
        if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
            throw ParseError(format("duplicate formal function argument '%1%' at %2%")
                % arg % pos);
    };
    void setName(Symbol & name);
    string showNamePos() const;
    COMMON_METHODS
};

struct ExprLet : Expr
{
    ExprAttrs * attrs;
    Expr * body;
    ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { };
    COMMON_METHODS
};

struct ExprWith : Expr
{
    Pos pos;
    Expr * attrs, * body;
    unsigned int prevWith;
    ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
    COMMON_METHODS
};

struct ExprIf : Expr
{
    Expr * cond, * then, * else_;
    ExprIf(Expr * cond, Expr * then, Expr * else_) : cond(cond), then(then), else_(else_) { };
    COMMON_METHODS
};

struct ExprAssert : Expr
{
    Pos pos;
    Expr * cond, * body;
    ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
    COMMON_METHODS
};

struct ExprOpNot : Expr
{
    Expr * e;
    ExprOpNot(Expr * e) : e(e) { };
    COMMON_METHODS
};

#define MakeBinOp(name, s) \
    struct Expr##name : Expr \
    { \
        Pos pos; \
        Expr * e1, * e2; \
        Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
        Expr##name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
        void show(std::ostream & str) \
        { \
            str << "(" << *e1 << " " s " " << *e2 << ")";   \
        } \
        void bindVars(const StaticEnv & env) \
        { \
            e1->bindVars(env); e2->bindVars(env); \
        } \
        void eval(EvalState & state, Env & env, Value & v); \
    };

MakeBinOp(App, "")
MakeBinOp(OpEq, "==")
MakeBinOp(OpNEq, "!=")
MakeBinOp(OpAnd, "&&")
MakeBinOp(OpOr, "||")
MakeBinOp(OpImpl, "->")
MakeBinOp(OpUpdate, "//")
MakeBinOp(OpConcatLists, "++")

struct ExprConcatStrings : Expr
{
    Pos pos;
    bool forceString;
    vector<Expr *> * es;
    ExprConcatStrings(const Pos & pos, bool forceString, vector<Expr *> * es)
        : pos(pos), forceString(forceString), es(es) { };
    COMMON_METHODS
};

struct ExprPos : Expr
{
    Pos pos;
    ExprPos(const Pos & pos) : pos(pos) { };
    COMMON_METHODS
};

/* Static environments are used to map variable names onto (level,
   displacement) pairs used to obtain the value of the variable at
   runtime. */
struct StaticEnv
{
    bool isWith;
    const StaticEnv * up;
    typedef std::map<Symbol, unsigned int> Vars;
    Vars vars;
    StaticEnv(bool isWith, const StaticEnv * up) : isWith(isWith), up(up) { };
};

}
<commit_msg>Modified MakeBinOp to no longer produce its name using concatenation and "##". Doing so prevents emacs tags from working, as well as makes the code extremely confusing for a newbie.<commit_after>#pragma once

#include "value.hh"
#include "symbol-table.hh"

#include <map>

namespace nix {

MakeError(EvalError, Error)
MakeError(ParseError, Error)
MakeError(IncompleteParseError, ParseError)
MakeError(AssertionError, EvalError)
MakeError(ThrownError, AssertionError)
MakeError(Abort, EvalError)
MakeError(TypeError, EvalError)
MakeError(UndefinedVarError, Error)
MakeError(RestrictedPathError, Error)

/* Position objects. */

struct Pos
{
    Symbol file;
    unsigned int line, column;
    Pos() : line(0), column(0) { };
    Pos(const Symbol & file, unsigned int line, unsigned int column)
        : file(file), line(line), column(column) { };
    operator bool() const
    {
        return line != 0;
    }
    bool operator < (const Pos & p2) const
    {
        if (!line) return p2.line;
        if (!p2.line) return false;
        int d = ((string) file).compare((string) p2.file);
        if (d < 0) return true;
        if (d > 0) return false;
        if (line < p2.line) return true;
        if (line > p2.line) return false;
        return column < p2.column;
    }
};

extern Pos noPos;

std::ostream & operator << (std::ostream & str, const Pos & pos);

struct Env;
struct Value;
class EvalState;
struct StaticEnv;

/* An attribute path is a sequence of attribute names. */
struct AttrName
{
    Symbol symbol;
    Expr * expr;
    AttrName(const Symbol & s) : symbol(s) {};
    AttrName(Expr * e) : expr(e) {};
};

typedef std::vector<AttrName> AttrPath;

string showAttrPath(const AttrPath & attrPath);

/* Abstract syntax of Nix expressions. */

struct Expr
{
    virtual ~Expr() { };
    virtual void show(std::ostream & str);
    virtual void bindVars(const StaticEnv & env);
    virtual void eval(EvalState & state, Env & env, Value & v);
    virtual Value * maybeThunk(EvalState & state, Env & env);
    virtual void setName(Symbol & name);
};

std::ostream & operator << (std::ostream & str, Expr & e);

#define COMMON_METHODS \
    void show(std::ostream & str); \
    void eval(EvalState & state, Env & env, Value & v); \
    void bindVars(const StaticEnv & env);

struct ExprInt : Expr
{
    NixInt n;
    Value v;
    ExprInt(NixInt n) : n(n) { mkInt(v, n); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprFloat : Expr
{
    NixFloat nf;
    Value v;
    ExprFloat(NixFloat nf) : nf(nf) { mkFloat(v, nf); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprString : Expr
{
    Symbol s;
    Value v;
    ExprString(const Symbol & s) : s(s) { mkString(v, s); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

/* Temporary class used during parsing of indented strings. */
struct ExprIndStr : Expr
{
    string s;
    ExprIndStr(const string & s) : s(s) { };
};

struct ExprPath : Expr
{
    string s;
    Value v;
    ExprPath(const string & s) : s(s) { mkPathNoCopy(v, this->s.c_str()); };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprVar : Expr
{
    Pos pos;
    Symbol name;

    /* Whether the variable comes from an environment (e.g. a rec, let
       or function argument) or from a "with". */
    bool fromWith;

    /* In the former case, the value is obtained by going `level'
       levels up from the current environment and getting the
       `displ'th value in that environment.  In the latter case, the
       value is obtained by getting the attribute named `name' from
       the set stored in the environment that is `level' levels up
       from the current one.*/
    unsigned int level;
    unsigned int displ;

    ExprVar(const Symbol & name) : name(name) { };
    ExprVar(const Pos & pos, const Symbol & name) : pos(pos), name(name) { };
    COMMON_METHODS
    Value * maybeThunk(EvalState & state, Env & env);
};

struct ExprSelect : Expr
{
    Pos pos;
    Expr * e, * def;
    AttrPath attrPath;
    ExprSelect(const Pos & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { };
    ExprSelect(const Pos & pos, Expr * e, const Symbol & name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
    COMMON_METHODS
};

struct ExprOpHasAttr : Expr
{
    Expr * e;
    AttrPath attrPath;
    ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { };
    COMMON_METHODS
};

struct ExprAttrs : Expr
{
    bool recursive;
    struct AttrDef {
        bool inherited;
        Expr * e;
        Pos pos;
        unsigned int displ; // displacement
        AttrDef(Expr * e, const Pos & pos, bool inherited=false)
            : inherited(inherited), e(e), pos(pos) { };
        AttrDef() { };
    };
    typedef std::map<Symbol, AttrDef> AttrDefs;
    AttrDefs attrs;
    struct DynamicAttrDef {
        Expr * nameExpr, * valueExpr;
        Pos pos;
        DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const Pos & pos)
            : nameExpr(nameExpr), valueExpr(valueExpr), pos(pos) { };
    };
    typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
    DynamicAttrDefs dynamicAttrs;
    ExprAttrs() : recursive(false) { };
    COMMON_METHODS
};

struct ExprList : Expr
{
    std::vector<Expr *> elems;
    ExprList() { };
    COMMON_METHODS
};

struct Formal
{
    Symbol name;
    Expr * def;
    Formal(const Symbol & name, Expr * def) : name(name), def(def) { };
};

struct Formals
{
    typedef std::list<Formal> Formals_;
    Formals_ formals;
    std::set<Symbol> argNames; // used during parsing
    bool ellipsis;
};

struct ExprLambda : Expr
{
    Pos pos;
    Symbol name;
    Symbol arg;
    bool matchAttrs;
    Formals * formals;
    Expr * body;
    ExprLambda(const Pos & pos, const Symbol & arg, bool matchAttrs, Formals * formals, Expr * body)
        : pos(pos), arg(arg), matchAttrs(matchAttrs), formals(formals), body(body)
    {
        if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
            throw ParseError(format("duplicate formal function argument '%1%' at %2%")
                % arg % pos);
    };
    void setName(Symbol & name);
    string showNamePos() const;
    COMMON_METHODS
};

struct ExprLet : Expr
{
    ExprAttrs * attrs;
    Expr * body;
    ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { };
    COMMON_METHODS
};

struct ExprWith : Expr
{
    Pos pos;
    Expr * attrs, * body;
    unsigned int prevWith;
    ExprWith(const Pos & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
    COMMON_METHODS
};

struct ExprIf : Expr
{
    Expr * cond, * then, * else_;
    ExprIf(Expr * cond, Expr * then, Expr * else_) : cond(cond), then(then), else_(else_) { };
    COMMON_METHODS
};

struct ExprAssert : Expr
{
    Pos pos;
    Expr * cond, * body;
    ExprAssert(const Pos & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
    COMMON_METHODS
};

struct ExprOpNot : Expr
{
    Expr * e;
    ExprOpNot(Expr * e) : e(e) { };
    COMMON_METHODS
};

#define MakeBinOp(name, s) \
    struct name : Expr \
    { \
        Pos pos; \
        Expr * e1, * e2; \
        name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
        name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
        void show(std::ostream & str) \
        { \
            str << "(" << *e1 << " " s " " << *e2 << ")";   \
        } \
        void bindVars(const StaticEnv & env) \
        { \
            e1->bindVars(env); e2->bindVars(env); \
        } \
        void eval(EvalState & state, Env & env, Value & v); \
    };

MakeBinOp(ExprApp, "")
MakeBinOp(ExprOpEq, "==")
MakeBinOp(ExprOpNEq, "!=")
MakeBinOp(ExprOpAnd, "&&")
MakeBinOp(ExprOpOr, "||")
MakeBinOp(ExprOpImpl, "->")
MakeBinOp(ExprOpUpdate, "//")
MakeBinOp(ExprOpConcatLists, "++")

struct ExprConcatStrings : Expr
{
    Pos pos;
    bool forceString;
    vector<Expr *> * es;
    ExprConcatStrings(const Pos & pos, bool forceString, vector<Expr *> * es)
        : pos(pos), forceString(forceString), es(es) { };
    COMMON_METHODS
};

struct ExprPos : Expr
{
    Pos pos;
    ExprPos(const Pos & pos) : pos(pos) { };
    COMMON_METHODS
};

/* Static environments are used to map variable names onto (level,
   displacement) pairs used to obtain the value of the variable at
   runtime. */
struct StaticEnv
{
    bool isWith;
    const StaticEnv * up;
    typedef std::map<Symbol, unsigned int> Vars;
    Vars vars;
    StaticEnv(bool isWith, const StaticEnv * up) : isWith(isWith), up(up) { };
};

}
<|endoftext|>


<commit_before>/*
 *    Copyright (c) 2019, The OpenThread Commissioner Authors.
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without
 *    modification, are permitted provided that the following conditions are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *    3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *    POSSIBILITY OF SUCH DAMAGE.
 */

#include "library/socket.hpp"

#include <memory.h>
#include <netinet/in.h>

#include "common/utils.hpp"
#include "library/logging.hpp"

namespace ot {

namespace commissioner {

static uint16_t GetSockPort(const sockaddr_storage &aSockAddr)
{
    if (aSockAddr.ss_family == AF_INET)
    {
        auto &addr4 = *reinterpret_cast<const sockaddr_in *>(&aSockAddr);
        return ntohs(addr4.sin_port);
    }
    else if (aSockAddr.ss_family == AF_INET6)
    {
        auto &addr6 = *reinterpret_cast<const sockaddr_in6 *>(&aSockAddr);
        return ntohs(addr6.sin6_port);
    }
    else
    {
        VerifyOrDie(false);
    }
}

Socket::Socket(struct event_base *aEventBase)
    : mEventBase(aEventBase)
    , mEventHandler(nullptr)
    , mIsConnected(false)
    , mSubType(MessageSubType::kNone)
{
    memset(&mEvent, 0, sizeof(mEvent));
}

Socket::~Socket()
{
    if (mEvent.ev_base != nullptr)
    {
        event_del(&mEvent);
    }
}

int Socket::Send(void *aSocket, const uint8_t *aBuf, size_t aLen)
{
    return reinterpret_cast<Socket *>(aSocket)->Send(aBuf, aLen);
}

int Socket::Receive(void *aSocket, uint8_t *aBuf, size_t aMaxLen)
{
    return reinterpret_cast<Socket *>(aSocket)->Receive(aBuf, aMaxLen);
}

void Socket::HandleEvent(evutil_socket_t, short aFlags, void *aSocket)
{
    auto socket = reinterpret_cast<Socket *>(aSocket);

    VerifyOrDie(socket->mEventHandler != nullptr);
    socket->mEventHandler(aFlags);
}

UdpSocket::UdpSocket(struct event_base *aEventBase)
    : Socket(aEventBase)
    , mIsBound(false)
{
    mbedtls_net_init(&mNetCtx);
}

UdpSocket::~UdpSocket()
{
    mbedtls_net_free(&mNetCtx);
}

UdpSocket::UdpSocket(UdpSocket &&aOther)
    : Socket(aOther.mEventBase)
    , mNetCtx(aOther.mNetCtx)
    , mIsBound(aOther.mIsBound)
{
    mbedtls_net_init(&aOther.mNetCtx);
}

int UdpSocket::Connect(const std::string &aHost, uint16_t aPort)
{
    auto portStr = std::to_string(aPort);

    // Free the fd if already opened.
    mbedtls_net_free(&mNetCtx);

    // Connect
    int rval = mbedtls_net_connect(&mNetCtx, aHost.c_str(), portStr.c_str(), MBEDTLS_NET_PROTO_UDP);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = mbedtls_net_set_nonblock(&mNetCtx)) == 0);

    // Setup event
    rval = event_assign(&mEvent, mEventBase, mNetCtx.fd, EV_PERSIST | EV_READ | EV_WRITE | EV_ET, HandleEvent, this);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = event_add(&mEvent, nullptr)) == 0);

exit:
    if (rval != 0)
    {
        mbedtls_net_free(&mNetCtx);
    }
    else
    {
        mIsConnected = true;
    }
    return rval;
}

int UdpSocket::Bind(const std::string &aBindIp, uint16_t aPort)
{
    auto portStr = std::to_string(aPort);

    // Free the fd if already opened.
    mbedtls_net_free(&mNetCtx);

    // Bind
    int rval = mbedtls_net_bind(&mNetCtx, aBindIp.c_str(), portStr.c_str(), MBEDTLS_NET_PROTO_UDP);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = mbedtls_net_set_nonblock(&mNetCtx)) == 0);

    // Setup Event
    rval = event_assign(&mEvent, mEventBase, mNetCtx.fd, EV_PERSIST | EV_READ | EV_WRITE | EV_ET, HandleEvent, this);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = event_add(&mEvent, nullptr)) == 0);

exit:
    if (rval != 0)
    {
        mbedtls_net_free(&mNetCtx);
    }
    else
    {
        mIsBound = true;
    }
    return rval;
}

uint16_t UdpSocket::GetLocalPort() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);

    VerifyOrDie(getsockname(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    return GetSockPort(addr);
}

Address UdpSocket::GetLocalAddr() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);
    Address          ret;

    VerifyOrDie(getsockname(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    SuccessOrDie(ret.Set(addr));
    return ret;
}

uint16_t UdpSocket::GetPeerPort() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);

    VerifyOrDie(mIsConnected);

    VerifyOrDie(getpeername(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    return GetSockPort(addr);
}

Address UdpSocket::GetPeerAddr() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);
    Address          ret;

    VerifyOrDie(mIsConnected);
    VerifyOrDie(getpeername(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    SuccessOrDie(ret.Set(addr));
    return ret;
}

int UdpSocket::Send(const uint8_t *aBuf, size_t aLen)
{
    VerifyOrDie(mNetCtx.fd >= 0);
    VerifyOrDie(mIsConnected);

    return mbedtls_net_send(&mNetCtx, aBuf, aLen);
}

int UdpSocket::Receive(uint8_t *aBuf, size_t aMaxLen)
{
    VerifyOrDie(mNetCtx.fd >= 0);
    VerifyOrDie(mIsConnected);

    return mbedtls_net_recv(&mNetCtx, aBuf, aMaxLen);
}

void UdpSocket::SetEventHandler(EventHandler aEventHandler)
{
    mEventHandler = [this, aEventHandler](short aFlags) {
        if (mIsBound && !mIsConnected && (aFlags & EV_READ))
        {
            mbedtls_net_context connectedCtx;
            mbedtls_net_init(&connectedCtx);

            // This will get 'mNetCtx' connected and returned as 'connectCtx'.
            int rval = mbedtls_net_accept(&mNetCtx, &connectedCtx, nullptr, 0, nullptr);
            if (rval != 0)
            {
                LOG_INFO(LOG_REGION_SOCKET, "UDP socket(={}) accept new connection failed: {}",
                         static_cast<void *>(this), rval);
            }
            else
            {
                mbedtls_net_free(&mNetCtx);

                // We know that 'connectedCtx' has the same fd as the original 'mNetCtx' before accept.
                mNetCtx      = connectedCtx;
                mIsConnected = true;
            }
        }

        // Do not handle event unless the socket is connected.
        if (mIsConnected)
        {
            aEventHandler(aFlags);
        }
    };
}

} // namespace commissioner

} // namespace ot
<commit_msg>[socket] fix deleting socket event when reconnect or rebind (#121)<commit_after>/*
 *    Copyright (c) 2019, The OpenThread Commissioner Authors.
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without
 *    modification, are permitted provided that the following conditions are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *    3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *    POSSIBILITY OF SUCH DAMAGE.
 */

#include "library/socket.hpp"

#include <memory.h>
#include <netinet/in.h>

#include "common/utils.hpp"
#include "library/logging.hpp"

namespace ot {

namespace commissioner {

static uint16_t GetSockPort(const sockaddr_storage &aSockAddr)
{
    if (aSockAddr.ss_family == AF_INET)
    {
        auto &addr4 = *reinterpret_cast<const sockaddr_in *>(&aSockAddr);
        return ntohs(addr4.sin_port);
    }
    else if (aSockAddr.ss_family == AF_INET6)
    {
        auto &addr6 = *reinterpret_cast<const sockaddr_in6 *>(&aSockAddr);
        return ntohs(addr6.sin6_port);
    }
    else
    {
        VerifyOrDie(false);
    }
}

Socket::Socket(struct event_base *aEventBase)
    : mEventBase(aEventBase)
    , mEventHandler(nullptr)
    , mIsConnected(false)
    , mSubType(MessageSubType::kNone)
{
    memset(&mEvent, 0, sizeof(mEvent));
}

Socket::~Socket()
{
    if (mEvent.ev_base != nullptr)
    {
        event_del(&mEvent);
    }
}

int Socket::Send(void *aSocket, const uint8_t *aBuf, size_t aLen)
{
    return reinterpret_cast<Socket *>(aSocket)->Send(aBuf, aLen);
}

int Socket::Receive(void *aSocket, uint8_t *aBuf, size_t aMaxLen)
{
    return reinterpret_cast<Socket *>(aSocket)->Receive(aBuf, aMaxLen);
}

void Socket::HandleEvent(evutil_socket_t, short aFlags, void *aSocket)
{
    auto socket = reinterpret_cast<Socket *>(aSocket);

    VerifyOrDie(socket->mEventHandler != nullptr);
    socket->mEventHandler(aFlags);
}

UdpSocket::UdpSocket(struct event_base *aEventBase)
    : Socket(aEventBase)
    , mIsBound(false)
{
    mbedtls_net_init(&mNetCtx);
}

UdpSocket::~UdpSocket()
{
    mbedtls_net_free(&mNetCtx);
}

UdpSocket::UdpSocket(UdpSocket &&aOther)
    : Socket(aOther.mEventBase)
    , mNetCtx(aOther.mNetCtx)
    , mIsBound(aOther.mIsBound)
{
    mbedtls_net_init(&aOther.mNetCtx);
}

int UdpSocket::Connect(const std::string &aHost, uint16_t aPort)
{
    auto portStr = std::to_string(aPort);

    // Free the fd if already opened.
    mbedtls_net_free(&mNetCtx);
    if (mEvent.ev_base != nullptr)
    {
        event_del(&mEvent);
    }

    // Connect
    int rval = mbedtls_net_connect(&mNetCtx, aHost.c_str(), portStr.c_str(), MBEDTLS_NET_PROTO_UDP);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = mbedtls_net_set_nonblock(&mNetCtx)) == 0);

    // Setup event
    rval = event_assign(&mEvent, mEventBase, mNetCtx.fd, EV_PERSIST | EV_READ | EV_WRITE | EV_ET, HandleEvent, this);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = event_add(&mEvent, nullptr)) == 0);

exit:
    if (rval != 0)
    {
        mbedtls_net_free(&mNetCtx);
    }
    else
    {
        mIsConnected = true;
    }
    return rval;
}

int UdpSocket::Bind(const std::string &aBindIp, uint16_t aPort)
{
    auto portStr = std::to_string(aPort);

    // Free the fd if already opened.
    mbedtls_net_free(&mNetCtx);
    if (mEvent.ev_base != nullptr)
    {
        event_del(&mEvent);
    }

    // Bind
    int rval = mbedtls_net_bind(&mNetCtx, aBindIp.c_str(), portStr.c_str(), MBEDTLS_NET_PROTO_UDP);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = mbedtls_net_set_nonblock(&mNetCtx)) == 0);

    // Setup Event
    rval = event_assign(&mEvent, mEventBase, mNetCtx.fd, EV_PERSIST | EV_READ | EV_WRITE | EV_ET, HandleEvent, this);
    VerifyOrExit(rval == 0);
    VerifyOrExit((rval = event_add(&mEvent, nullptr)) == 0);

exit:
    if (rval != 0)
    {
        mbedtls_net_free(&mNetCtx);
    }
    else
    {
        mIsBound = true;
    }
    return rval;
}

uint16_t UdpSocket::GetLocalPort() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);

    VerifyOrDie(getsockname(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    return GetSockPort(addr);
}

Address UdpSocket::GetLocalAddr() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);
    Address          ret;

    VerifyOrDie(getsockname(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    SuccessOrDie(ret.Set(addr));
    return ret;
}

uint16_t UdpSocket::GetPeerPort() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);

    VerifyOrDie(mIsConnected);

    VerifyOrDie(getpeername(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    return GetSockPort(addr);
}

Address UdpSocket::GetPeerAddr() const
{
    sockaddr_storage addr;
    socklen_t        len = sizeof(sockaddr_storage);
    Address          ret;

    VerifyOrDie(mIsConnected);
    VerifyOrDie(getpeername(mNetCtx.fd, reinterpret_cast<sockaddr *>(&addr), &len) == 0);
    SuccessOrDie(ret.Set(addr));
    return ret;
}

int UdpSocket::Send(const uint8_t *aBuf, size_t aLen)
{
    VerifyOrDie(mNetCtx.fd >= 0);
    VerifyOrDie(mIsConnected);

    return mbedtls_net_send(&mNetCtx, aBuf, aLen);
}

int UdpSocket::Receive(uint8_t *aBuf, size_t aMaxLen)
{
    VerifyOrDie(mNetCtx.fd >= 0);
    VerifyOrDie(mIsConnected);

    return mbedtls_net_recv(&mNetCtx, aBuf, aMaxLen);
}

void UdpSocket::SetEventHandler(EventHandler aEventHandler)
{
    mEventHandler = [this, aEventHandler](short aFlags) {
        if (mIsBound && !mIsConnected && (aFlags & EV_READ))
        {
            mbedtls_net_context connectedCtx;
            mbedtls_net_init(&connectedCtx);

            // This will get 'mNetCtx' connected and returned as 'connectCtx'.
            int rval = mbedtls_net_accept(&mNetCtx, &connectedCtx, nullptr, 0, nullptr);
            if (rval != 0)
            {
                LOG_INFO(LOG_REGION_SOCKET, "UDP socket(={}) accept new connection failed: {}",
                         static_cast<void *>(this), rval);
            }
            else
            {
                mbedtls_net_free(&mNetCtx);

                // We know that 'connectedCtx' has the same fd as the original 'mNetCtx' before accept.
                mNetCtx      = connectedCtx;
                mIsConnected = true;
            }
        }

        // Do not handle event unless the socket is connected.
        if (mIsConnected)
        {
            aEventHandler(aFlags);
        }
    };
}

} // namespace commissioner

} // namespace ot
<|endoftext|>


<commit_before>#include "loadCellModule.h"

loadCellModule::loadCellModule(const char* sensorID, int dOutPin, int pdSckPin, int gain)
:
	Module(sensorID),
	dOutPin_(dOutPin),
	pdSckPin_(pdSckPin),
	gain_(gain),
	transducer_(dOutPin_, pdSckPin_, gain_),
	offset_(0),
	constant_(1.),
	calibrationModule_(this, "Calibrate", &loadCellModule::calibrate), // individual calibration module
	tareModule_(this, "Tare", &loadCellModule::tare)
{};

loadCellModule::loadCellModule(void)
:
	// need a dummy because the library doesn't support a default constructor (fail)
	// use the LED_PIN which will never do anything
	transducer_(14, 14, 128)
{};

loadCellModule::~loadCellModule(void) {};

// read the value of the transducer as an integer
// int loadCellModule::getValue(void)
// {
// 	return int( (transducer_.read() - offset_)/constant_ );
// }

// return the reading without casting to an int
double loadCellModule::getReading(void)
{
	return transducer_.get_units();
}

// set sensor reading to zero
void loadCellModule::tare(void)
{
	#ifdef DEBUG_PRINTOUT
	Serial.print(getIdentifier());
	Serial.print(": Setting reading to zero at the current excitation of ");
	Serial.println(getReading());
	#endif

	transducer_.tare();
	offset_ = transducer_.get_offset();
}

// set the calibration constant
void loadCellModule::calibrate(double newConstant)
{
	#ifdef DEBUG_PRINTOUT
	Serial.print(getIdentifier());
	Serial.print(": Calibrating with value ");
	Serial.println(newConstant);
	#endif

	transducer_.set_scale(newConstant);
	constant_ = newConstant;
}

void loadCellModule::powerDown(void)
{
	transducer_.power_down();
}

void loadCellModule::powerUp(void)
{
	transducer_.power_up();
}
<commit_msg>Minor fix in loadCell<commit_after>#include "loadCellModule.h"

loadCellModule::loadCellModule(const char* sensorID, int dOutPin, int pdSckPin, int gain)
:
	Module(sensorID),
	dOutPin_(dOutPin),
	pdSckPin_(pdSckPin),
	gain_(gain),
	transducer_(dOutPin_, pdSckPin_, gain_),
	offset_(0),
	constant_(1.),
	calibrationModule_(this, "Calibrate", &loadCellModule::calibrate), // individual calibration module
	tareModule_(this, "Tare", &loadCellModule::tare)
{};

loadCellModule::loadCellModule(void)
:
	// need a dummy because the library doesn't support a default constructor (fail)
	// use the LED_PIN which will never do anything
	transducer_(14, 14, 128)
{};

loadCellModule::~loadCellModule(void) {};

// read the value of the transducer as an integer
// int loadCellModule::getValue(void)
// {
// 	return int( (transducer_.read() - offset_)/constant_ );
// }

// return the reading without casting to an int
double loadCellModule::getReading(void)
{
	// use the get_value method as that returns a double, not a float like
	// get_units does. That means scaling needs to be done here.
	return transducer_.get_value()/constant_;
}

// set sensor reading to zero
void loadCellModule::tare(void)
{
	#ifdef DEBUG_PRINTOUT
	Serial.print(getIdentifier());
	Serial.print(": Setting reading to zero at the current excitation of ");
	Serial.println(getReading());
	#endif

	transducer_.tare();
	offset_ = transducer_.get_offset();
}

// set the calibration constant
void loadCellModule::calibrate(double newConstant)
{
	#ifdef DEBUG_PRINTOUT
	Serial.print(getIdentifier());
	Serial.print(": Calibrating with value ");
	Serial.println(newConstant);
	#endif

	transducer_.set_scale(newConstant);
	constant_ = newConstant;
}

void loadCellModule::powerDown(void)
{
	transducer_.power_down();
}

void loadCellModule::powerUp(void)
{
	transducer_.power_up();
}
<|endoftext|>


<commit_before>#include <stan/math/fwd/mat.hpp>
#include <gtest/gtest.h>

using stan::math::matrix_fd;
using stan::math::fvar;

// INCOMPLETE - need to finish writing up second test

TEST(MathMatrix, matrix_exp) {

    fvar<double> a;
    a.val_ = 0.0;
    a.d_ = 1.0;
    matrix_fd input(1,1), output;

    input << a;
    output = matrix_exp(input);

    EXPECT_EQ(1.0, output(0,0).val_);
    EXPECT_EQ(1.0, output(0,0).d_);

    fvar<double> b;
    b.val_ = 1.0;
    b.d_ = 2.0;

    input << b;
    output = matrix_exp(input);

    EXPECT_EQ(exp(1.0), output(0,0).val_);
    EXPECT_EQ(b.d_ * output(0,0).val_, output(0,0).d_);

}

TEST(MathMatrix, matrix_exp2) {

    // example from Moler & Van Loan, 2003
    matrix_fd input(2,2), output;
    fvar<double> a, b, c, d;

    a.val_ = -49.0;
    b.val_ = 24.0;
    c.val_ = -64.0;
    d.val_ = 31.0;
    a.d_ = 1.0;
    b.d_ = 1.0;
    c.d_ = 1.0;
    d.d_ = 1.0;

    input << a, b,
             c, d;

    output = matrix_exp(input);

    //m2 << -.735759, .551819,
    //-1.471518, 1.103638;

    EXPECT_FLOAT_EQ(-0.735759, output(0,0).val_);
    EXPECT_FLOAT_EQ(0.551819, output(0,1).val_);
    EXPECT_FLOAT_EQ(-1.471518, output(1,0).val_);
    EXPECT_FLOAT_EQ(1.103638, output(1,1).val_);
    /*EXPECT_EQ(-0.735759, output(0,0).d_);
    EXPECT_EQ(0.551819, output(0,1).d_);
    EXPECT_EQ(-1.47152, output(1,0).d_);
    EXPECT_EQ(1.103654, output(1,1).d_);*/

}
<commit_msg>update unit test for matrix_exp_test forward mode with example from Moler & van Loan<commit_after>#include <stan/math/fwd/mat.hpp>
#include <gtest/gtest.h>

using stan::math::matrix_fd;
using stan::math::fvar;

// INCOMPLETE - need to finish writing up second test

TEST(MathMatrix, matrix_exp) {

    fvar<double> a;
    a.val_ = 0.0;
    a.d_ = 1.0;
    matrix_fd input(1,1), output;

    input << a;
    output = matrix_exp(input);

    EXPECT_EQ(1.0, output(0,0).val_);
    EXPECT_EQ(1.0, output(0,0).d_);

    fvar<double> b;
    b.val_ = 1.0;
    b.d_ = 2.0;

    input << b;
    output = matrix_exp(input);

    EXPECT_EQ(exp(1.0), output(0,0).val_);
    EXPECT_EQ(b.d_ * output(0,0).val_, output(0,0).d_);

}

TEST(MathMatrix, matrix_exp2) {

    // example from Moler & Van Loan, 2003, section 3
    matrix_fd input_diag(2,2), input(2,2), output;
    fvar<double> a, b;
    a.val_ = -1.0;
    b.val_ = -17.0;
    a.d_ = 1.0;
    b.d_ = 1.0;

    input << -2*a + 3*b, 1.5*a - 1.5*b,
            -4*a + 4*b, 3*a - 2*b;

    output = matrix_exp(input);

    EXPECT_FLOAT_EQ(-0.735759, output(0,0).val_);
    EXPECT_FLOAT_EQ(0.551819, output(0,1).val_);
    EXPECT_FLOAT_EQ(-1.471518, output(1,0).val_);
    EXPECT_FLOAT_EQ(1.103638, output(1,1).val_);

    // note: in this particular example, derivatives
    // is the same as the value, due to the way the
    // input matrix was constructed.
    EXPECT_FLOAT_EQ(-0.735759, output(0,0).d_);
    EXPECT_FLOAT_EQ(0.551819, output(0,1).d_);
    EXPECT_FLOAT_EQ(-1.471518, output(1,0).d_);
    EXPECT_FLOAT_EQ(1.103638, output(1,1).d_);

}
<|endoftext|>


<commit_before>#include "observer.h"
#include "application.h"

#define internal static
#define local_persist static

void AXLibConstructObserver(ax_application *Application, ObserverCallback Callback)
{
    AXError Result = AXObserverCreate(Application->PID, Callback, &Application->Observer.Ref);
    Application->Observer.Valid = (Result == kAXErrorSuccess);
    Application->Observer.Application = Application;
}

void AXLibStartObserver(ax_observer *Observer)
{
    if(!CFRunLoopContainsSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(Observer->Ref), kCFRunLoopDefaultMode))
        CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(Observer->Ref), kCFRunLoopDefaultMode);
}

AXError AXLibAddObserverNotification(ax_observer *Observer, AXUIElementRef Ref, CFStringRef Notification, void *Reference)
{
    return AXObserverAddNotification(Observer->Ref, Ref, Notification, Reference);
}

void AXLibRemoveObserverNotification(ax_observer *Observer, AXUIElementRef Ref, CFStringRef Notification)
{
    AXObserverRemoveNotification(Observer->Ref, Ref, Notification);
}

void AXLibStopObserver(ax_observer *Observer)
{
    /* NOTE(koekeishiya): CFRunLoopSourceInvalidate removes the source from all run-loops, ignoring run-loops that no longer exist.
                          Replaces CFRunLoopRemoveSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(Observer->Ref), kCFRunLoopDefaultMode); */
    CFRunLoopSourceInvalidate(AXObserverGetRunLoopSource(Observer->Ref));
}

void AXLibDestroyObserver(ax_observer *Observer)
{
    CFRelease(Observer->Ref);
    Observer->Valid = false;
    Observer->Ref = NULL;
    Observer->Application = NULL;
}
<commit_msg>remove unnecessary clearing of variables<commit_after>#include "observer.h"
#include "application.h"

#define internal static
#define local_persist static

void AXLibConstructObserver(ax_application *Application, ObserverCallback Callback)
{
    AXError Result = AXObserverCreate(Application->PID, Callback, &Application->Observer.Ref);
    Application->Observer.Valid = (Result == kAXErrorSuccess);
    Application->Observer.Application = Application;
}

void AXLibStartObserver(ax_observer *Observer)
{
    if(!CFRunLoopContainsSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(Observer->Ref), kCFRunLoopDefaultMode))
        CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(Observer->Ref), kCFRunLoopDefaultMode);
}

AXError AXLibAddObserverNotification(ax_observer *Observer, AXUIElementRef Ref, CFStringRef Notification, void *Reference)
{
    return AXObserverAddNotification(Observer->Ref, Ref, Notification, Reference);
}

void AXLibRemoveObserverNotification(ax_observer *Observer, AXUIElementRef Ref, CFStringRef Notification)
{
    AXObserverRemoveNotification(Observer->Ref, Ref, Notification);
}

void AXLibStopObserver(ax_observer *Observer)
{
    /* NOTE(koekeishiya): CFRunLoopSourceInvalidate removes the source from all run-loops, ignoring run-loops that no longer exist.
                          Replaces CFRunLoopRemoveSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(Observer->Ref), kCFRunLoopDefaultMode); */
    CFRunLoopSourceInvalidate(AXObserverGetRunLoopSource(Observer->Ref));
}

void AXLibDestroyObserver(ax_observer *Observer)
{
    if(Observer->Ref)
        CFRelease(Observer->Ref);

    Observer->Valid = false;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/host_dispatcher.h"

#include <map>

#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "ppapi/c/private/ppb_proxy_private.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/proxy/host_var_serialization_rules.h"
#include "ppapi/proxy/interface_list.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/resource_creation_proxy.h"

namespace ppapi {
namespace proxy {

namespace {

typedef std::map<PP_Instance, HostDispatcher*> InstanceToDispatcherMap;
InstanceToDispatcherMap* g_instance_to_dispatcher = NULL;

typedef std::map<PP_Module, HostDispatcher*> ModuleToDispatcherMap;
ModuleToDispatcherMap* g_module_to_dispatcher = NULL;

PP_Bool ReserveInstanceID(PP_Module module, PP_Instance instance) {
  // Default to returning true (usable) failure. Otherwise, if there's some
  // kind of communication error or the plugin just crashed, we'll get into an
  // infinite loop generating new instnace IDs since we think they're all in
  // use.
  ModuleToDispatcherMap::const_iterator found =
      g_module_to_dispatcher->find(module);
  if (found == g_module_to_dispatcher->end()) {
    NOTREACHED();
    return PP_TRUE;
  }

  bool usable = true;
  if (!found->second->Send(new PpapiMsg_ReserveInstanceId(instance, &usable)))
    return PP_TRUE;
  return PP_FromBool(usable);
}

// Saves the state of the given bool and puts it back when it goes out of
// scope.
class BoolRestorer {
 public:
  BoolRestorer(bool* var) : var_(var), old_value_(*var) {
  }
  ~BoolRestorer() {
    *var_ = old_value_;
  }
 private:
  bool* var_;
  bool old_value_;
};

}  // namespace

HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle,
                               PP_Module module,
                               GetInterfaceFunc local_get_interface)
    : Dispatcher(remote_process_handle, local_get_interface),
      pp_module_(module),
      ppb_proxy_(NULL),
      allow_plugin_reentrancy_(false) {
  if (!g_module_to_dispatcher)
    g_module_to_dispatcher = new ModuleToDispatcherMap;
  (*g_module_to_dispatcher)[pp_module_] = this;

  const PPB_Var* var_interface =
      static_cast<const PPB_Var*>(local_get_interface(PPB_VAR_INTERFACE));
  SetSerializationRules(new HostVarSerializationRules(var_interface, module));

  ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>(
      local_get_interface(PPB_PROXY_PRIVATE_INTERFACE));
  DCHECK(ppb_proxy_) << "The proxy interface should always be supported.";

  ppb_proxy_->SetReserveInstanceIDCallback(pp_module_, &ReserveInstanceID);
}

HostDispatcher::~HostDispatcher() {
  g_module_to_dispatcher->erase(pp_module_);
}

bool HostDispatcher::InitHostWithChannel(
    Delegate* delegate,
    const IPC::ChannelHandle& channel_handle,
    bool is_client,
    const ppapi::Preferences& preferences) {
  if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client))
    return false;
  Send(new PpapiMsg_SetPreferences(preferences));
  return true;
}

// static
HostDispatcher* HostDispatcher::GetForInstance(PP_Instance instance) {
  if (!g_instance_to_dispatcher)
    return NULL;
  InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
      instance);
  if (found == g_instance_to_dispatcher->end())
    return NULL;
  return found->second;
}

// static
void HostDispatcher::SetForInstance(PP_Instance instance,
                                    HostDispatcher* dispatcher) {
  if (!g_instance_to_dispatcher)
    g_instance_to_dispatcher = new InstanceToDispatcherMap;
  (*g_instance_to_dispatcher)[instance] = dispatcher;
}

// static
void HostDispatcher::RemoveForInstance(PP_Instance instance) {
  if (!g_instance_to_dispatcher)
    return;
  InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
      instance);
  if (found != g_instance_to_dispatcher->end())
    g_instance_to_dispatcher->erase(found);
}

bool HostDispatcher::IsPlugin() const {
  return false;
}

bool HostDispatcher::Send(IPC::Message* msg) {
  TRACE_EVENT2("ppapi proxy", "HostDispatcher::Send",
               "Class", IPC_MESSAGE_ID_CLASS(msg->type()),
               "Line", IPC_MESSAGE_ID_LINE(msg->type()));
  // Prevent the dispatcher from going away during the call. Scenarios
  // where this could happen include a Send for a sync message which while
  // waiting for the reply, dispatches an incoming ExecuteScript call which
  // destroys the plugin module and in turn the dispatcher,
  ScopedModuleReference ref(this);

  if (!allow_plugin_reentrancy_)
    msg->set_unblock(false);
  return Dispatcher::Send(msg);
}

bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) {
  TRACE_EVENT2("ppapi proxy", "HostDispatcher::OnMessageReceived",
               "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
               "Line", IPC_MESSAGE_ID_LINE(msg.type()));
  // We only want to allow reentrancy when the most recent message from the
  // plugin was a scripting message. We save the old state of the flag on the
  // stack in case we're (we are the host) being reentered ourselves. The flag
  // is set to false here for all messages, and then the scripting API will
  // explicitly set it to true during processing of those messages that can be
  // reentered.
  BoolRestorer restorer(&allow_plugin_reentrancy_);
  allow_plugin_reentrancy_ = false;

  return Dispatcher::OnMessageReceived(msg);
}

void HostDispatcher::OnChannelError() {
  Dispatcher::OnChannelError();  // Stop using the channel.

  // Tell the host about the crash so it can clean up and display notification.
  ppb_proxy_->PluginCrashed(pp_module());
}

const void* HostDispatcher::GetProxiedInterface(const std::string& iface_name) {
  const void* proxied_interface =
      InterfaceList::GetInstance()->GetInterfaceForPPP(iface_name);
  if (!proxied_interface)
    return NULL;  // Don't have a proxy for this interface, don't query further.

  PluginSupportedMap::iterator iter(plugin_supported_.find(iface_name));
  if (iter == plugin_supported_.end()) {
    // Need to query. Cache the result so we only do this once.
    bool supported = false;

    bool previous_reentrancy_value = allow_plugin_reentrancy_;
    allow_plugin_reentrancy_ = true;
    Send(new PpapiMsg_SupportsInterface(iface_name, &supported));
    allow_plugin_reentrancy_ = previous_reentrancy_value;

    std::pair<PluginSupportedMap::iterator, bool> iter_success_pair;
    iter_success_pair = plugin_supported_.insert(
        PluginSupportedMap::value_type(iface_name, supported));
    iter = iter_success_pair.first;
  }
  if (iter->second)
    return proxied_interface;
  return NULL;
}

void HostDispatcher::OnInvalidMessageReceived() {
  // TODO(brettw) bug 95345 kill the plugin when an invalid message is
  // received.
}

// ScopedModuleReference -------------------------------------------------------

ScopedModuleReference::ScopedModuleReference(Dispatcher* dispatcher) {
  DCHECK(!dispatcher->IsPlugin());
  dispatcher_ = static_cast<HostDispatcher*>(dispatcher);
  dispatcher_->ppb_proxy()->AddRefModule(dispatcher_->pp_module());
}

ScopedModuleReference::~ScopedModuleReference() {
  dispatcher_->ppb_proxy()->ReleaseModule(dispatcher_->pp_module());
}

}  // namespace proxy
}  // namespace ppapi
<commit_msg>Restore comments about reentrancy in the HostDispatcher::Send function<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/proxy/host_dispatcher.h"

#include <map>

#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "ppapi/c/private/ppb_proxy_private.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/proxy/host_var_serialization_rules.h"
#include "ppapi/proxy/interface_list.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/resource_creation_proxy.h"

namespace ppapi {
namespace proxy {

namespace {

typedef std::map<PP_Instance, HostDispatcher*> InstanceToDispatcherMap;
InstanceToDispatcherMap* g_instance_to_dispatcher = NULL;

typedef std::map<PP_Module, HostDispatcher*> ModuleToDispatcherMap;
ModuleToDispatcherMap* g_module_to_dispatcher = NULL;

PP_Bool ReserveInstanceID(PP_Module module, PP_Instance instance) {
  // Default to returning true (usable) failure. Otherwise, if there's some
  // kind of communication error or the plugin just crashed, we'll get into an
  // infinite loop generating new instnace IDs since we think they're all in
  // use.
  ModuleToDispatcherMap::const_iterator found =
      g_module_to_dispatcher->find(module);
  if (found == g_module_to_dispatcher->end()) {
    NOTREACHED();
    return PP_TRUE;
  }

  bool usable = true;
  if (!found->second->Send(new PpapiMsg_ReserveInstanceId(instance, &usable)))
    return PP_TRUE;
  return PP_FromBool(usable);
}

// Saves the state of the given bool and puts it back when it goes out of
// scope.
class BoolRestorer {
 public:
  BoolRestorer(bool* var) : var_(var), old_value_(*var) {
  }
  ~BoolRestorer() {
    *var_ = old_value_;
  }
 private:
  bool* var_;
  bool old_value_;
};

}  // namespace

HostDispatcher::HostDispatcher(base::ProcessHandle remote_process_handle,
                               PP_Module module,
                               GetInterfaceFunc local_get_interface)
    : Dispatcher(remote_process_handle, local_get_interface),
      pp_module_(module),
      ppb_proxy_(NULL),
      allow_plugin_reentrancy_(false) {
  if (!g_module_to_dispatcher)
    g_module_to_dispatcher = new ModuleToDispatcherMap;
  (*g_module_to_dispatcher)[pp_module_] = this;

  const PPB_Var* var_interface =
      static_cast<const PPB_Var*>(local_get_interface(PPB_VAR_INTERFACE));
  SetSerializationRules(new HostVarSerializationRules(var_interface, module));

  ppb_proxy_ = reinterpret_cast<const PPB_Proxy_Private*>(
      local_get_interface(PPB_PROXY_PRIVATE_INTERFACE));
  DCHECK(ppb_proxy_) << "The proxy interface should always be supported.";

  ppb_proxy_->SetReserveInstanceIDCallback(pp_module_, &ReserveInstanceID);
}

HostDispatcher::~HostDispatcher() {
  g_module_to_dispatcher->erase(pp_module_);
}

bool HostDispatcher::InitHostWithChannel(
    Delegate* delegate,
    const IPC::ChannelHandle& channel_handle,
    bool is_client,
    const ppapi::Preferences& preferences) {
  if (!Dispatcher::InitWithChannel(delegate, channel_handle, is_client))
    return false;
  Send(new PpapiMsg_SetPreferences(preferences));
  return true;
}

// static
HostDispatcher* HostDispatcher::GetForInstance(PP_Instance instance) {
  if (!g_instance_to_dispatcher)
    return NULL;
  InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
      instance);
  if (found == g_instance_to_dispatcher->end())
    return NULL;
  return found->second;
}

// static
void HostDispatcher::SetForInstance(PP_Instance instance,
                                    HostDispatcher* dispatcher) {
  if (!g_instance_to_dispatcher)
    g_instance_to_dispatcher = new InstanceToDispatcherMap;
  (*g_instance_to_dispatcher)[instance] = dispatcher;
}

// static
void HostDispatcher::RemoveForInstance(PP_Instance instance) {
  if (!g_instance_to_dispatcher)
    return;
  InstanceToDispatcherMap::iterator found = g_instance_to_dispatcher->find(
      instance);
  if (found != g_instance_to_dispatcher->end())
    g_instance_to_dispatcher->erase(found);
}

bool HostDispatcher::IsPlugin() const {
  return false;
}

bool HostDispatcher::Send(IPC::Message* msg) {
  TRACE_EVENT2("ppapi proxy", "HostDispatcher::Send",
               "Class", IPC_MESSAGE_ID_CLASS(msg->type()),
               "Line", IPC_MESSAGE_ID_LINE(msg->type()));
  // Prevent the dispatcher from going away during the call. Scenarios
  // where this could happen include a Send for a sync message which while
  // waiting for the reply, dispatches an incoming ExecuteScript call which
  // destroys the plugin module and in turn the dispatcher.
  ScopedModuleReference ref(this);

  // Normal sync messages are set to unblock, which would normally cause the
  // plugin to be reentered to process them. We only want to do this when we
  // know the plugin is in a state to accept reentrancy. Since the plugin side
  // never clears this flag on messages it sends, we can't get deadlock, but we
  // may still get reentrancy in the host as a result.

  if (!allow_plugin_reentrancy_)
    msg->set_unblock(false);
  return Dispatcher::Send(msg);
}

bool HostDispatcher::OnMessageReceived(const IPC::Message& msg) {
  TRACE_EVENT2("ppapi proxy", "HostDispatcher::OnMessageReceived",
               "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
               "Line", IPC_MESSAGE_ID_LINE(msg.type()));
  // We only want to allow reentrancy when the most recent message from the
  // plugin was a scripting message. We save the old state of the flag on the
  // stack in case we're (we are the host) being reentered ourselves. The flag
  // is set to false here for all messages, and then the scripting API will
  // explicitly set it to true during processing of those messages that can be
  // reentered.
  BoolRestorer restorer(&allow_plugin_reentrancy_);
  allow_plugin_reentrancy_ = false;

  return Dispatcher::OnMessageReceived(msg);
}

void HostDispatcher::OnChannelError() {
  Dispatcher::OnChannelError();  // Stop using the channel.

  // Tell the host about the crash so it can clean up and display notification.
  ppb_proxy_->PluginCrashed(pp_module());
}

const void* HostDispatcher::GetProxiedInterface(const std::string& iface_name) {
  const void* proxied_interface =
      InterfaceList::GetInstance()->GetInterfaceForPPP(iface_name);
  if (!proxied_interface)
    return NULL;  // Don't have a proxy for this interface, don't query further.

  PluginSupportedMap::iterator iter(plugin_supported_.find(iface_name));
  if (iter == plugin_supported_.end()) {
    // Need to query. Cache the result so we only do this once.
    bool supported = false;

    bool previous_reentrancy_value = allow_plugin_reentrancy_;
    allow_plugin_reentrancy_ = true;
    Send(new PpapiMsg_SupportsInterface(iface_name, &supported));
    allow_plugin_reentrancy_ = previous_reentrancy_value;

    std::pair<PluginSupportedMap::iterator, bool> iter_success_pair;
    iter_success_pair = plugin_supported_.insert(
        PluginSupportedMap::value_type(iface_name, supported));
    iter = iter_success_pair.first;
  }
  if (iter->second)
    return proxied_interface;
  return NULL;
}

void HostDispatcher::OnInvalidMessageReceived() {
  // TODO(brettw) bug 95345 kill the plugin when an invalid message is
  // received.
}

// ScopedModuleReference -------------------------------------------------------

ScopedModuleReference::ScopedModuleReference(Dispatcher* dispatcher) {
  DCHECK(!dispatcher->IsPlugin());
  dispatcher_ = static_cast<HostDispatcher*>(dispatcher);
  dispatcher_->ppb_proxy()->AddRefModule(dispatcher_->pp_module());
}

ScopedModuleReference::~ScopedModuleReference() {
  dispatcher_->ppb_proxy()->ReleaseModule(dispatcher_->pp_module());
}

}  // namespace proxy
}  // namespace ppapi
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/tests/test_fullscreen.h"

#include <stdio.h>
#include <string.h>
#include <string>

#include "ppapi/c/dev/ppb_testing_dev.h"
#include "ppapi/c/dev/ppb_fullscreen_dev.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/point.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"

REGISTER_TEST_CASE(Fullscreen);

namespace {

bool HasMidScreen(const pp::Rect& position, const pp::Size& screen_size) {
  static int32_t mid_x = screen_size.width() / 2;
  static int32_t mid_y = screen_size.height() / 2;
  return (position.Contains(mid_x, mid_y));
}

}  // namespace

TestFullscreen::TestFullscreen(TestingInstance* instance)
    : TestCase(instance),
      error_(),
      screen_mode_(instance),
      fullscreen_pending_(false),
      normal_pending_(false),
      saw_first_fullscreen_didchangeview(false),
      graphics2d_fullscreen_(instance, pp::Size(10, 10), false),
      graphics2d_normal_(instance, pp::Size(15, 15), false),
      set_fullscreen_true_callback_(instance->pp_instance()),
      fullscreen_callback_(instance->pp_instance()),
      normal_callback_(instance->pp_instance()) {
  screen_mode_.GetScreenSize(&screen_size_);
}

bool TestFullscreen::Init() {
  if (graphics2d_fullscreen_.is_null() && graphics2d_normal_.is_null())
    return false;
  return InitTestingInterface();
}

void TestFullscreen::RunTest() {
  RUN_TEST(GetScreenSize);
  RUN_TEST(NormalToFullscreenToNormal);
}

bool TestFullscreen::GotError() {
  return !error_.empty();
}

std::string TestFullscreen::Error() {
  std::string last_error = error_;
  error_.clear();
  return last_error;
}

std::string TestFullscreen::TestGetScreenSize() {
  if (screen_size_.width() < 320 || screen_size_.width() > 2560)
    return ReportError("screen_size.width()", screen_size_.width());
  if (screen_size_.height() < 200 || screen_size_.height() > 2048)
    return ReportError("screen_size.height()", screen_size_.height());
  PASS();
}

std::string TestFullscreen::TestNormalToFullscreenToNormal() {
  // 0. Start in normal mode.
  if (screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() at start", true);

  // 1. Switch to fullscreen.
  // This is only allowed within a context of a user gesture (e.g. mouse click).
  if (screen_mode_.SetFullscreen(true))
    return ReportError("SetFullscreen(true) outside of user gesture", true);
  // The transition is asynchronous and ends at the next DidChangeView().
  // No graphics devices can be bound while in transition.
  instance_->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
  // HandleInputEvent() will call SetFullscreen(true).
  // DidChangeView() will call the callback once in fullscreen mode.
  fullscreen_callback_.WaitForResult();
  if (GotError())
    return Error();
  if (fullscreen_pending_)
    return "fullscreen_pending_ has not been reset";
  if (!screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in fullscreen", false);
  if (!instance_->BindGraphics(graphics2d_fullscreen_))
    return ReportError("BindGraphics() in fullscreen", false);

  // 2. Stay in fullscreen. No change.
  if (screen_mode_.SetFullscreen(true))
    return ReportError("SetFullscreen(true) in fullscreen", true);
  if (!screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in fullscreen^2", false);

  // 3. Switch to normal.
  // The transition is asynchronous and ends at DidChangeView().
  // No graphics devices can be bound while in transition.
  normal_pending_ = true;
  if (!screen_mode_.SetFullscreen(false))
    return ReportError("SetFullscreen(false) in fullscreen", false);
  // Normal is now pending, so additional requests should fail.
  if (screen_mode_.SetFullscreen(false))
    return ReportError("SetFullscreen(false) in normal pending", true);
  if (screen_mode_.SetFullscreen(true))
    return ReportError("SetFullscreen(true) in normal pending", true);
  if (instance_->BindGraphics(graphics2d_normal_))
    return ReportError("BindGraphics() in normal transition", true);
  if (!screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in normal transition", false);
  // DidChangeView() will call the callback once out of fullscreen mode.
  normal_callback_.WaitForResult();
  if (normal_pending_)
    return "normal_pending_ has not been reset";
  if (screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in normal", true);
  if (!instance_->BindGraphics(graphics2d_fullscreen_))
    return ReportError("BindGraphics() in normal", false);

  // 4. Stay in normal. No change.
  if (screen_mode_.SetFullscreen(false))
    return ReportError("SetFullscreen(false) in normal", true);
  if (screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in normal^2", true);

  PASS();
}

void TestFullscreen::FailFullscreenTest(const std::string& error) {
  screen_mode_.SetFullscreen(false);
  fullscreen_pending_ = false;
  error_ = error;
  pp::Module::Get()->core()->CallOnMainThread(0, fullscreen_callback_);
}

// Transition to fullscreen can only happen when processing a user gesture.
bool TestFullscreen::HandleInputEvent(const pp::InputEvent& event) {
  // We only let mouse events through and only mouse clicks count.
  if (event.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN &&
      event.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP)
    return false;
  // We got the gesture. No need to handle any more events.
  instance_->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE);
  fullscreen_pending_ = true;
  if (!screen_mode_.SetFullscreen(true)) {
    FailFullscreenTest(ReportError("SetFullscreen(true) in normal", false));
    return false;
  }
  // Fullscreen is now pending, so additional requests should fail.
  if (screen_mode_.SetFullscreen(true)) {
    FailFullscreenTest(
        ReportError("SetFullscreen(true) in fullscreen pending", true));
    return false;
  }
  if (screen_mode_.SetFullscreen(false)) {
    FailFullscreenTest(
        ReportError("SetFullscreen(false) in fullscreen pending", true));
  }
  // No graphics devices can be bound while in transition.
  if (instance_->BindGraphics(graphics2d_fullscreen_)) {
    FailFullscreenTest(
        ReportError("BindGraphics() in fullscreen transition", true));
    return false;
  }
  if (screen_mode_.IsFullscreen()) {
    FailFullscreenTest(
        ReportError("IsFullscreen() in fullscreen transtion", true));
    return false;
  }
  // DidChangeView() will complete the transition to fullscreen.
  return false;
}

// Transitions to/from fullscreen is asynchornous ending at DidChangeView.
// When going to fullscreen, two DidChangeView calls are generated:
// one for moving the plugin to the middle of window and one for stretching
// the window and placing the plugin in the middle of the screen.
// WebKit does not change the plugin size, but Pepper does explicitly set
// it to screen width and height when SetFullscreen(true) is called and
// resets it back when ViewChanged is received indicating that we exited
// fullscreen.
// NOTE: The number of DidChangeView calls for <object> might be different.
void TestFullscreen::DidChangeView(const pp::Rect& position,
                                   const pp::Rect& clip) {
  if (normal_position_.IsEmpty())
    normal_position_ = position;

  if (fullscreen_pending_ && !saw_first_fullscreen_didchangeview) {
    saw_first_fullscreen_didchangeview = true;
    if (!screen_mode_.IsFullscreen())
      FailFullscreenTest("DidChangeView1 is not in fullscreen");
    if (position.size() != screen_size_)
      FailFullscreenTest("DidChangeView1 does not have screen size");
    // Wait for the 2nd DidChangeView.
  } else if (fullscreen_pending_) {
    fullscreen_pending_ = false;
    saw_first_fullscreen_didchangeview = false;
    if (!screen_mode_.IsFullscreen())
      FailFullscreenTest("DidChangeView2 is not in fullscreen");
    else if (!HasMidScreen(position, screen_size_))
      FailFullscreenTest("DidChangeView2 is not in the middle of the screen");
    else if (position.size() != screen_size_)
      FailFullscreenTest("DidChangeView2 does not have screen size");
    // NOTE: we cannot reliably test for clip size being equal to the screen
    // because it might be affected by JS console, info bars, etc.
    else
      pp::Module::Get()->core()->CallOnMainThread(0, fullscreen_callback_);
  } else if (normal_pending_) {
    normal_pending_ = false;
    if (screen_mode_.IsFullscreen())
      error_ = "DidChangeview is in fullscreen";
    else if (position != normal_position_)
      error_ = "DidChangeView position is not normal";
    pp::Module::Get()->core()->CallOnMainThread(0, normal_callback_);
  }
}
<commit_msg>PPAPI Fullscreen: update ppapi_test to match the behavior after RenderWidget::is_fullscreen (used in DidChangeView to detect fullscreen mode) was implemented. Review URL: http://codereview.chromium.org/8301010<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/tests/test_fullscreen.h"

#include <stdio.h>
#include <string.h>
#include <string>

#include "ppapi/c/dev/ppb_testing_dev.h"
#include "ppapi/c/dev/ppb_fullscreen_dev.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/point.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"

REGISTER_TEST_CASE(Fullscreen);

namespace {

bool HasMidScreen(const pp::Rect& position, const pp::Size& screen_size) {
  static int32_t mid_x = screen_size.width() / 2;
  static int32_t mid_y = screen_size.height() / 2;
  return (position.Contains(mid_x, mid_y));
}

}  // namespace

TestFullscreen::TestFullscreen(TestingInstance* instance)
    : TestCase(instance),
      error_(),
      screen_mode_(instance),
      fullscreen_pending_(false),
      normal_pending_(false),
      saw_first_fullscreen_didchangeview(false),
      graphics2d_fullscreen_(instance, pp::Size(10, 10), false),
      graphics2d_normal_(instance, pp::Size(15, 15), false),
      set_fullscreen_true_callback_(instance->pp_instance()),
      fullscreen_callback_(instance->pp_instance()),
      normal_callback_(instance->pp_instance()) {
  screen_mode_.GetScreenSize(&screen_size_);
}

bool TestFullscreen::Init() {
  if (graphics2d_fullscreen_.is_null() && graphics2d_normal_.is_null())
    return false;
  return InitTestingInterface();
}

void TestFullscreen::RunTest() {
  RUN_TEST(GetScreenSize);
  RUN_TEST(NormalToFullscreenToNormal);
}

bool TestFullscreen::GotError() {
  return !error_.empty();
}

std::string TestFullscreen::Error() {
  std::string last_error = error_;
  error_.clear();
  return last_error;
}

std::string TestFullscreen::TestGetScreenSize() {
  if (screen_size_.width() < 320 || screen_size_.width() > 2560)
    return ReportError("screen_size.width()", screen_size_.width());
  if (screen_size_.height() < 200 || screen_size_.height() > 2048)
    return ReportError("screen_size.height()", screen_size_.height());
  PASS();
}

std::string TestFullscreen::TestNormalToFullscreenToNormal() {
  // 0. Start in normal mode.
  if (screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() at start", true);

  // 1. Switch to fullscreen.
  // This is only allowed within a context of a user gesture (e.g. mouse click).
  if (screen_mode_.SetFullscreen(true))
    return ReportError("SetFullscreen(true) outside of user gesture", true);
  // The transition is asynchronous and ends at the next DidChangeView().
  // No graphics devices can be bound while in transition.
  instance_->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
  // HandleInputEvent() will call SetFullscreen(true).
  // DidChangeView() will call the callback once in fullscreen mode.
  fullscreen_callback_.WaitForResult();
  if (GotError())
    return Error();
  if (fullscreen_pending_)
    return "fullscreen_pending_ has not been reset";
  if (!screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in fullscreen", false);
  if (!instance_->BindGraphics(graphics2d_fullscreen_))
    return ReportError("BindGraphics() in fullscreen", false);

  // 2. Stay in fullscreen. No change.
  if (screen_mode_.SetFullscreen(true))
    return ReportError("SetFullscreen(true) in fullscreen", true);
  if (!screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in fullscreen^2", false);

  // 3. Switch to normal.
  // The transition is asynchronous and ends at DidChangeView().
  // No graphics devices can be bound while in transition.
  normal_pending_ = true;
  if (!screen_mode_.SetFullscreen(false))
    return ReportError("SetFullscreen(false) in fullscreen", false);
  // Normal is now pending, so additional requests should fail.
  if (screen_mode_.SetFullscreen(false))
    return ReportError("SetFullscreen(false) in normal pending", true);
  if (screen_mode_.SetFullscreen(true))
    return ReportError("SetFullscreen(true) in normal pending", true);
  if (instance_->BindGraphics(graphics2d_normal_))
    return ReportError("BindGraphics() in normal transition", true);
  if (!screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in normal transition", false);
  // DidChangeView() will call the callback once out of fullscreen mode.
  normal_callback_.WaitForResult();
  if (normal_pending_)
    return "normal_pending_ has not been reset";
  if (screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in normal", true);
  if (!instance_->BindGraphics(graphics2d_fullscreen_))
    return ReportError("BindGraphics() in normal", false);

  // 4. Stay in normal. No change.
  if (screen_mode_.SetFullscreen(false))
    return ReportError("SetFullscreen(false) in normal", true);
  if (screen_mode_.IsFullscreen())
    return ReportError("IsFullscreen() in normal^2", true);

  PASS();
}

void TestFullscreen::FailFullscreenTest(const std::string& error) {
  screen_mode_.SetFullscreen(false);
  fullscreen_pending_ = false;
  error_ = error;
  pp::Module::Get()->core()->CallOnMainThread(0, fullscreen_callback_);
}

// Transition to fullscreen can only happen when processing a user gesture.
bool TestFullscreen::HandleInputEvent(const pp::InputEvent& event) {
  // We only let mouse events through and only mouse clicks count.
  if (event.GetType() != PP_INPUTEVENT_TYPE_MOUSEDOWN &&
      event.GetType() != PP_INPUTEVENT_TYPE_MOUSEUP)
    return false;
  // We got the gesture. No need to handle any more events.
  instance_->ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE);
  fullscreen_pending_ = true;
  if (!screen_mode_.SetFullscreen(true)) {
    FailFullscreenTest(ReportError("SetFullscreen(true) in normal", false));
    return false;
  }
  // Fullscreen is now pending, so additional requests should fail.
  if (screen_mode_.SetFullscreen(true)) {
    FailFullscreenTest(
        ReportError("SetFullscreen(true) in fullscreen pending", true));
    return false;
  }
  if (screen_mode_.SetFullscreen(false)) {
    FailFullscreenTest(
        ReportError("SetFullscreen(false) in fullscreen pending", true));
  }
  // No graphics devices can be bound while in transition.
  if (instance_->BindGraphics(graphics2d_fullscreen_)) {
    FailFullscreenTest(
        ReportError("BindGraphics() in fullscreen transition", true));
    return false;
  }
  if (screen_mode_.IsFullscreen()) {
    FailFullscreenTest(
        ReportError("IsFullscreen() in fullscreen transtion", true));
    return false;
  }
  // DidChangeView() will complete the transition to fullscreen.
  return false;
}

// Transitions to/from fullscreen is asynchornous ending at DidChangeView.
// When going to fullscreen, two DidChangeView calls are generated:
// one for moving the plugin to the middle of window and one for stretching
// the window and placing the plugin in the middle of the screen.
// WebKit does not change the plugin size, but Pepper does explicitly set
// it to screen width and height when SetFullscreen(true) is called and
// resets it back when ViewChanged is received indicating that we exited
// fullscreen.
// NOTE: The number of DidChangeView calls for <object> might be different.
void TestFullscreen::DidChangeView(const pp::Rect& position,
                                   const pp::Rect& clip) {
  if (normal_position_.IsEmpty())
    normal_position_ = position;

  if (fullscreen_pending_ && !saw_first_fullscreen_didchangeview) {
    saw_first_fullscreen_didchangeview = true;
    if (screen_mode_.IsFullscreen())
      FailFullscreenTest("DidChangeView1 is in fullscreen");
    if (position.size() != screen_size_)
      FailFullscreenTest("DidChangeView1 does not have screen size");
    // Wait for the 2nd DidChangeView.
  } else if (fullscreen_pending_) {
    fullscreen_pending_ = false;
    saw_first_fullscreen_didchangeview = false;
    if (!screen_mode_.IsFullscreen())
      FailFullscreenTest("DidChangeView2 is not in fullscreen");
    else if (!HasMidScreen(position, screen_size_))
      FailFullscreenTest("DidChangeView2 is not in the middle of the screen");
    else if (position.size() != screen_size_)
      FailFullscreenTest("DidChangeView2 does not have screen size");
    // NOTE: we cannot reliably test for clip size being equal to the screen
    // because it might be affected by JS console, info bars, etc.
    else
      pp::Module::Get()->core()->CallOnMainThread(0, fullscreen_callback_);
  } else if (normal_pending_) {
    normal_pending_ = false;
    if (screen_mode_.IsFullscreen())
      error_ = "DidChangeview is in fullscreen";
    else if (position != normal_position_)
      error_ = "DidChangeView position is not normal";
    pp::Module::Get()->core()->CallOnMainThread(0, normal_callback_);
  }
}
<|endoftext|>


<commit_before><commit_msg>[Mac] Log registers with stackdump in debug crashes.<commit_after><|endoftext|>


<commit_before>//----------------------------  data_out_rotation.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2000 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  data_out_rotation.cc  ---------------------------

#include <base/quadrature_lib.h>
#include <lac/vector.h>
#include <numerics/data_out_rotation.h>
#include <grid/tria.h>
#include <dofs/dof_handler.h>
#include <dofs/dof_accessor.h>
#include <grid/tria_iterator.h>
#include <fe/fe.h>
#include <fe/fe_values.h>

#ifdef DEAL_II_USE_MT
#include <base/thread_management.h>
#endif

#include <strstream>

template <int dim>
void DataOutRotation<dim>::build_some_patches (Data data)
{
  QTrapez<1>     q_trapez;
  QIterated<dim> patch_points (q_trapez, data.n_subdivisions);

  FEValues<dim> fe_patch_values(dofs->get_fe(),
				patch_points,
				update_values);

  const unsigned int n_patches_per_circle = data.n_patches_per_circle;

				   // another abbreviation denoting
				   // the number of q_points in each
				   // direction
  const unsigned int n_points = data.n_subdivisions+1;

				   // set up an array that holds the
				   // directions in the plane of
				   // rotation in which we will put
				   // points in the whole domain (not
				   // the rotationally reduced one in
				   // which the computation took
				   // place. for simplicity add the
				   // initial direction at the end
				   // again
  const double pi = 3.14159265358979323846;
  vector<Point<dim+1> > angle_directions (n_patches_per_circle+1);
  for (unsigned int i=0; i<=n_patches_per_circle; ++i)
    {
      angle_directions[i][0] = cos(2*pi*i/n_patches_per_circle);
      angle_directions[i][1] = sin(2*pi*i/n_patches_per_circle);
    };

  unsigned int cell_number = 0;
  typename vector<DataOutBase::Patch<dim+1> >::iterator patch = patches.begin();
  typename DoFHandler<dim>::cell_iterator cell=first_cell();

				   // get first cell in this thread
  for (unsigned int i=0; (i<data.this_thread)&&(cell != dofs->end()); ++i)
    {
      advance (patch, n_patches_per_circle);
      ++cell_number;
      cell=next_cell(cell);
    }

  				   // now loop over all cells and
				   // actually create the patches
  for (; cell != dofs->end(); )
    {
      for (unsigned int angle=0; angle<n_patches_per_circle; ++angle, ++patch)
	{
	  Assert (patch != patches.end(), ExcInternalError());

					   // first compute the
					   // vertices of the
					   // patch. note that they
					   // will have to be computed
					   // from the vertices of the
					   // cell, which has one
					   // dimension less, however.
	  switch (dim)
	    {
	      case 1:
	      {
		const double r1 = cell->vertex(0)(0),
			     r2 = cell->vertex(1)(0);
		Assert (r1 >= 0, ExcRadialVariableHasNegativeValues(r1));
		Assert (r2 >= 0, ExcRadialVariableHasNegativeValues(r2));

		patch->vertices[0] = r1*angle_directions[angle];
		patch->vertices[1] = r2*angle_directions[angle];
		patch->vertices[2] = r2*angle_directions[angle+1];
		patch->vertices[3] = r1*angle_directions[angle+1];

		break;
	      };

	      case 2:
	      {
		for (unsigned int vertex=0;
		     vertex<GeometryInfo<dim>::vertices_per_cell;
		     ++vertex)
		  {
		    const Point<dim> v = cell->vertex(vertex);

						     // make sure that the
						     // radial variable does
						     // attain negative
						     // values
		    Assert (v(0) >= 0, ExcRadialVariableHasNegativeValues(v(0)));

						     // now set the vertices
						     // of the patch
		    patch->vertices[vertex] = v(0) * angle_directions[angle];
		    patch->vertices[vertex][2] = v(1);

		    patch->vertices[vertex+GeometryInfo<dim>::vertices_per_cell]
		      = v(0) * angle_directions[angle+1];
		    patch->vertices[vertex+GeometryInfo<dim>::vertices_per_cell][2]
		      = v(1);
		  };

		break;
	      };

	      default:
		    Assert (false, ExcNotImplemented());
	    };

					   // then fill in data
	  if (data.n_datasets > 0)
	    {
	      fe_patch_values.reinit (cell);

					       // first fill dof_data
	      for (unsigned int dataset=0; dataset<dof_data.size(); ++dataset)
		{
		  if (data.n_components == 1)
		    {
		      fe_patch_values.get_function_values (*dof_data[dataset].data,
							   data.patch_values);
		      switch (dim)
			{
			  case 1:
				for (unsigned int x=0; x<n_points; ++x)
				  for (unsigned int y=0; y<n_points; ++y)
				    patch->data(dataset,
						x*n_points + y)
					= data.patch_values[x];
				break;

			  case 2:
				for (unsigned int x=0; x<n_points; ++x)
				  for (unsigned int y=0; y<n_points; ++y)
				    for (unsigned int z=0; z<n_points; ++z)
				      patch->data(dataset,
						  x*n_points*n_points +
						  y*n_points +
						  z)
					= data.patch_values[x*n_points+z];
				break;

			  default:
				Assert (false, ExcNotImplemented());
			};
		    }
		  else
						     // system of components
		    {
		      fe_patch_values.get_function_values (*dof_data[dataset].data,
							   data.patch_values_system);
		      for (unsigned int component=0; component<data.n_components;
			   ++component)
			{
			  switch (dim)
			    {
			      case 1:
				    for (unsigned int x=0; x<n_points; ++x)
				      for (unsigned int y=0; y<n_points; ++y)
					patch->data(dataset*data.n_components+component,
						    x*n_points + y)
					    = data.patch_values_system[x](component);
				    break;

			      case 2:
				    for (unsigned int x=0; x<n_points; ++x)
				      for (unsigned int y=0; y<n_points; ++y)
					for (unsigned int z=0; z<n_points; ++z)
					  patch->data(dataset*data.n_components+component,
						      x*n_points*n_points +
						      y*n_points +
						      z)
					    = data.patch_values_system[x*n_points+z](component);
				    break;

			      default:
				    Assert (false, ExcNotImplemented());
			    };
			};
		    };
		};

					       // then do the cell data
	      for (unsigned int dataset=0; dataset<cell_data.size(); ++dataset)
		{
		  const double value = (*cell_data[dataset].data)(cell_number);
		  switch (dim)
		    {
		      case 1:
			    for (unsigned int x=0; x<n_points; ++x)
			      for (unsigned int y=0; y<n_points; ++y)
				patch->data(dataset+dof_data.size()*data.n_components,
					    x*n_points +
					    y)
				  = value;
			    break;

		      case 2:
			    for (unsigned int x=0; x<n_points; ++x)
			      for (unsigned int y=0; y<n_points; ++y)
				for (unsigned int z=0; z<n_points; ++z)
				  patch->data(dataset+dof_data.size()*data.n_components,
					      x*n_points*n_points +
					      y*n_points +
					      z)
				    = value;
			    break;

		      default:
			    Assert (false, ExcNotImplemented());
		    };
		};
	    };
	};

				       // next cell (patch) in this
				       // thread. note that we have
				       // already advanced the patches
				       // for the present cell,
				       // i.e. we only have to skip
				       // the cells belonging to other
				       // threads, not the ones
				       // belonging to this thread.
      const int skip_threads = static_cast<signed int>(data.n_threads)-1;
      for (int i=0; (i<skip_threads) && (cell != dofs->end()); ++i)
	advance (patch, n_patches_per_circle);

				       // however, cell and cell
				       // number have not yet been
				       // increased
      for (unsigned int i=0; (i<data.n_threads) && (cell != dofs->end()); ++i)
	{
	  ++cell_number;
	  cell=next_cell(cell);
	};
    };
};

#if deal_II_dimension == 3

template <>
void DataOutRotation<3>::build_some_patches (Data)
{
				   // would this function make any
				   // sense after all? who would want
				   // to output/compute in four space
				   // dimensions?
  Assert (false, ExcNotImplemented());
};

#endif

template <int dim>
void DataOutRotation<dim>::build_patches (const unsigned int n_patches_per_circle,
					  const unsigned int n_subdivisions,
					  const unsigned int n_threads_)
{
  Assert (n_subdivisions >= 1,
	  ExcInvalidNumberOfSubdivisions(n_subdivisions));

  typedef DataOut_DoFData<dim,dim+1> BaseClass;
  Assert (dofs != 0, typename BaseClass::ExcNoDoFHandlerSelected());

#ifdef DEAL_II_USE_MT
  const unsigned int n_threads = n_threads_;
#else
				   // access this variable to avoid
				   // compiler warning about unused
				   // var:
  (void)n_threads_;
  const unsigned int n_threads = 1;
#endif

				   // before we start the loop:
				   // create a quadrature rule that
				   // actually has the points on this
				   // patch
  QTrapez<1>     q_trapez;
  QIterated<dim> patch_points (q_trapez, n_subdivisions);

  const unsigned int n_q_points     = patch_points.n_quadrature_points;
  const unsigned int n_components   = dofs->get_fe().n_components();
  const unsigned int n_datasets     = dof_data.size() * n_components +
				      cell_data.size();

				   // clear the patches array
  if (true)
    {
      vector<DataOutBase::Patch<dim+1> > dummy;
      patches.swap (dummy);
    };

				   // first count the cells we want to
				   // create patches of and make sure
				   // there is enough memory for that
  unsigned int n_patches = 0;
  for (DoFHandler<dim>::cell_iterator cell=first_cell();
       cell != dofs->end();
       cell = next_cell(cell))
    ++n_patches;
				   // then also take into account that
				   // we want more than one patch to
				   // come out of every cell, as they
				   // are repeated around the axis of
				   // rotation
  n_patches *= n_patches_per_circle;

  vector<Data> thread_data(n_threads);

				   // init data for the threads
  for (unsigned int i=0;i<n_threads;++i)
    {
      thread_data[i].n_threads            = n_threads;
      thread_data[i].this_thread          = i;
      thread_data[i].n_components         = n_components;
      thread_data[i].n_datasets           = n_datasets;
      thread_data[i].n_patches_per_circle = n_patches_per_circle;
      thread_data[i].n_subdivisions       = n_subdivisions;
      thread_data[i].patch_values.resize (n_q_points);
      thread_data[i].patch_values_system.resize (n_q_points);

      for (unsigned int k=0; k<n_q_points; ++k)
	thread_data[i].patch_values_system[k].reinit(n_components);
    }

				   // create the patches with default
				   // values. note that the evaluation
				   // points on the cell have to be
				   // repeated in angular direction
  DataOutBase::Patch<dim+1>  default_patch;
  default_patch.n_subdivisions = n_subdivisions;
  default_patch.data.reinit (n_datasets,
			     n_q_points * (n_subdivisions+1));
  patches.insert (patches.end(), n_patches, default_patch);

#ifdef DEAL_II_USE_MT

  Threads::ThreadManager thread_manager;
  for (unsigned int l=0;l<n_threads;++l)
    Threads::spawn (thread_manager,
		    Threads::encapsulate (&DataOutRotation<dim>::build_some_patches)
		    .collect_args (this, thread_data[l]));
  thread_manager.wait();

				   // just one thread
#else
  build_some_patches(thread_data[0]);
#endif
};

template <int dim>
typename DoFHandler<dim>::cell_iterator
DataOutRotation<dim>::first_cell ()
{
  return dofs->begin_active ();
};

template <int dim>
typename DoFHandler<dim>::cell_iterator
DataOutRotation<dim>::next_cell (const typename DoFHandler<dim>::cell_iterator &cell)
{
				   // convert the iterator to an
				   // active_iterator and advance
				   // this to the next active cell
  typename DoFHandler<dim>::active_cell_iterator active_cell = cell;
  ++active_cell;
  return active_cell;
};

// explicit instantiations
template class DataOutRotation<deal_II_dimension>;

<commit_msg>Avoid error with undefined fabs/sin/cos/sqrt with gcc2.97<commit_after>//----------------------------  data_out_rotation.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2000 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  data_out_rotation.cc  ---------------------------

#include <base/quadrature_lib.h>
#include <lac/vector.h>
#include <numerics/data_out_rotation.h>
#include <grid/tria.h>
#include <dofs/dof_handler.h>
#include <dofs/dof_accessor.h>
#include <grid/tria_iterator.h>
#include <fe/fe.h>
#include <fe/fe_values.h>

#ifdef DEAL_II_USE_MT
#include <base/thread_management.h>
#endif

#include <strstream>
#include <cmath>

template <int dim>
void DataOutRotation<dim>::build_some_patches (Data data)
{
  QTrapez<1>     q_trapez;
  QIterated<dim> patch_points (q_trapez, data.n_subdivisions);

  FEValues<dim> fe_patch_values(dofs->get_fe(),
				patch_points,
				update_values);

  const unsigned int n_patches_per_circle = data.n_patches_per_circle;

				   // another abbreviation denoting
				   // the number of q_points in each
				   // direction
  const unsigned int n_points = data.n_subdivisions+1;

				   // set up an array that holds the
				   // directions in the plane of
				   // rotation in which we will put
				   // points in the whole domain (not
				   // the rotationally reduced one in
				   // which the computation took
				   // place. for simplicity add the
				   // initial direction at the end
				   // again
  const double pi = 3.14159265358979323846;
  vector<Point<dim+1> > angle_directions (n_patches_per_circle+1);
  for (unsigned int i=0; i<=n_patches_per_circle; ++i)
    {
      angle_directions[i][0] = cos(2*pi*i/n_patches_per_circle);
      angle_directions[i][1] = sin(2*pi*i/n_patches_per_circle);
    };

  unsigned int cell_number = 0;
  typename vector<DataOutBase::Patch<dim+1> >::iterator patch = patches.begin();
  typename DoFHandler<dim>::cell_iterator cell=first_cell();

				   // get first cell in this thread
  for (unsigned int i=0; (i<data.this_thread)&&(cell != dofs->end()); ++i)
    {
      advance (patch, n_patches_per_circle);
      ++cell_number;
      cell=next_cell(cell);
    }

  				   // now loop over all cells and
				   // actually create the patches
  for (; cell != dofs->end(); )
    {
      for (unsigned int angle=0; angle<n_patches_per_circle; ++angle, ++patch)
	{
	  Assert (patch != patches.end(), ExcInternalError());

					   // first compute the
					   // vertices of the
					   // patch. note that they
					   // will have to be computed
					   // from the vertices of the
					   // cell, which has one
					   // dimension less, however.
	  switch (dim)
	    {
	      case 1:
	      {
		const double r1 = cell->vertex(0)(0),
			     r2 = cell->vertex(1)(0);
		Assert (r1 >= 0, ExcRadialVariableHasNegativeValues(r1));
		Assert (r2 >= 0, ExcRadialVariableHasNegativeValues(r2));

		patch->vertices[0] = r1*angle_directions[angle];
		patch->vertices[1] = r2*angle_directions[angle];
		patch->vertices[2] = r2*angle_directions[angle+1];
		patch->vertices[3] = r1*angle_directions[angle+1];

		break;
	      };

	      case 2:
	      {
		for (unsigned int vertex=0;
		     vertex<GeometryInfo<dim>::vertices_per_cell;
		     ++vertex)
		  {
		    const Point<dim> v = cell->vertex(vertex);

						     // make sure that the
						     // radial variable does
						     // attain negative
						     // values
		    Assert (v(0) >= 0, ExcRadialVariableHasNegativeValues(v(0)));

						     // now set the vertices
						     // of the patch
		    patch->vertices[vertex] = v(0) * angle_directions[angle];
		    patch->vertices[vertex][2] = v(1);

		    patch->vertices[vertex+GeometryInfo<dim>::vertices_per_cell]
		      = v(0) * angle_directions[angle+1];
		    patch->vertices[vertex+GeometryInfo<dim>::vertices_per_cell][2]
		      = v(1);
		  };

		break;
	      };

	      default:
		    Assert (false, ExcNotImplemented());
	    };

					   // then fill in data
	  if (data.n_datasets > 0)
	    {
	      fe_patch_values.reinit (cell);

					       // first fill dof_data
	      for (unsigned int dataset=0; dataset<dof_data.size(); ++dataset)
		{
		  if (data.n_components == 1)
		    {
		      fe_patch_values.get_function_values (*dof_data[dataset].data,
							   data.patch_values);
		      switch (dim)
			{
			  case 1:
				for (unsigned int x=0; x<n_points; ++x)
				  for (unsigned int y=0; y<n_points; ++y)
				    patch->data(dataset,
						x*n_points + y)
					= data.patch_values[x];
				break;

			  case 2:
				for (unsigned int x=0; x<n_points; ++x)
				  for (unsigned int y=0; y<n_points; ++y)
				    for (unsigned int z=0; z<n_points; ++z)
				      patch->data(dataset,
						  x*n_points*n_points +
						  y*n_points +
						  z)
					= data.patch_values[x*n_points+z];
				break;

			  default:
				Assert (false, ExcNotImplemented());
			};
		    }
		  else
						     // system of components
		    {
		      fe_patch_values.get_function_values (*dof_data[dataset].data,
							   data.patch_values_system);
		      for (unsigned int component=0; component<data.n_components;
			   ++component)
			{
			  switch (dim)
			    {
			      case 1:
				    for (unsigned int x=0; x<n_points; ++x)
				      for (unsigned int y=0; y<n_points; ++y)
					patch->data(dataset*data.n_components+component,
						    x*n_points + y)
					    = data.patch_values_system[x](component);
				    break;

			      case 2:
				    for (unsigned int x=0; x<n_points; ++x)
				      for (unsigned int y=0; y<n_points; ++y)
					for (unsigned int z=0; z<n_points; ++z)
					  patch->data(dataset*data.n_components+component,
						      x*n_points*n_points +
						      y*n_points +
						      z)
					    = data.patch_values_system[x*n_points+z](component);
				    break;

			      default:
				    Assert (false, ExcNotImplemented());
			    };
			};
		    };
		};

					       // then do the cell data
	      for (unsigned int dataset=0; dataset<cell_data.size(); ++dataset)
		{
		  const double value = (*cell_data[dataset].data)(cell_number);
		  switch (dim)
		    {
		      case 1:
			    for (unsigned int x=0; x<n_points; ++x)
			      for (unsigned int y=0; y<n_points; ++y)
				patch->data(dataset+dof_data.size()*data.n_components,
					    x*n_points +
					    y)
				  = value;
			    break;

		      case 2:
			    for (unsigned int x=0; x<n_points; ++x)
			      for (unsigned int y=0; y<n_points; ++y)
				for (unsigned int z=0; z<n_points; ++z)
				  patch->data(dataset+dof_data.size()*data.n_components,
					      x*n_points*n_points +
					      y*n_points +
					      z)
				    = value;
			    break;

		      default:
			    Assert (false, ExcNotImplemented());
		    };
		};
	    };
	};

				       // next cell (patch) in this
				       // thread. note that we have
				       // already advanced the patches
				       // for the present cell,
				       // i.e. we only have to skip
				       // the cells belonging to other
				       // threads, not the ones
				       // belonging to this thread.
      const int skip_threads = static_cast<signed int>(data.n_threads)-1;
      for (int i=0; (i<skip_threads) && (cell != dofs->end()); ++i)
	advance (patch, n_patches_per_circle);

				       // however, cell and cell
				       // number have not yet been
				       // increased
      for (unsigned int i=0; (i<data.n_threads) && (cell != dofs->end()); ++i)
	{
	  ++cell_number;
	  cell=next_cell(cell);
	};
    };
};

#if deal_II_dimension == 3

template <>
void DataOutRotation<3>::build_some_patches (Data)
{
				   // would this function make any
				   // sense after all? who would want
				   // to output/compute in four space
				   // dimensions?
  Assert (false, ExcNotImplemented());
};

#endif

template <int dim>
void DataOutRotation<dim>::build_patches (const unsigned int n_patches_per_circle,
					  const unsigned int n_subdivisions,
					  const unsigned int n_threads_)
{
  Assert (n_subdivisions >= 1,
	  ExcInvalidNumberOfSubdivisions(n_subdivisions));

  typedef DataOut_DoFData<dim,dim+1> BaseClass;
  Assert (dofs != 0, typename BaseClass::ExcNoDoFHandlerSelected());

#ifdef DEAL_II_USE_MT
  const unsigned int n_threads = n_threads_;
#else
				   // access this variable to avoid
				   // compiler warning about unused
				   // var:
  (void)n_threads_;
  const unsigned int n_threads = 1;
#endif

				   // before we start the loop:
				   // create a quadrature rule that
				   // actually has the points on this
				   // patch
  QTrapez<1>     q_trapez;
  QIterated<dim> patch_points (q_trapez, n_subdivisions);

  const unsigned int n_q_points     = patch_points.n_quadrature_points;
  const unsigned int n_components   = dofs->get_fe().n_components();
  const unsigned int n_datasets     = dof_data.size() * n_components +
				      cell_data.size();

				   // clear the patches array
  if (true)
    {
      vector<DataOutBase::Patch<dim+1> > dummy;
      patches.swap (dummy);
    };

				   // first count the cells we want to
				   // create patches of and make sure
				   // there is enough memory for that
  unsigned int n_patches = 0;
  for (DoFHandler<dim>::cell_iterator cell=first_cell();
       cell != dofs->end();
       cell = next_cell(cell))
    ++n_patches;
				   // then also take into account that
				   // we want more than one patch to
				   // come out of every cell, as they
				   // are repeated around the axis of
				   // rotation
  n_patches *= n_patches_per_circle;

  vector<Data> thread_data(n_threads);

				   // init data for the threads
  for (unsigned int i=0;i<n_threads;++i)
    {
      thread_data[i].n_threads            = n_threads;
      thread_data[i].this_thread          = i;
      thread_data[i].n_components         = n_components;
      thread_data[i].n_datasets           = n_datasets;
      thread_data[i].n_patches_per_circle = n_patches_per_circle;
      thread_data[i].n_subdivisions       = n_subdivisions;
      thread_data[i].patch_values.resize (n_q_points);
      thread_data[i].patch_values_system.resize (n_q_points);

      for (unsigned int k=0; k<n_q_points; ++k)
	thread_data[i].patch_values_system[k].reinit(n_components);
    }

				   // create the patches with default
				   // values. note that the evaluation
				   // points on the cell have to be
				   // repeated in angular direction
  DataOutBase::Patch<dim+1>  default_patch;
  default_patch.n_subdivisions = n_subdivisions;
  default_patch.data.reinit (n_datasets,
			     n_q_points * (n_subdivisions+1));
  patches.insert (patches.end(), n_patches, default_patch);

#ifdef DEAL_II_USE_MT

  Threads::ThreadManager thread_manager;
  for (unsigned int l=0;l<n_threads;++l)
    Threads::spawn (thread_manager,
		    Threads::encapsulate (&DataOutRotation<dim>::build_some_patches)
		    .collect_args (this, thread_data[l]));
  thread_manager.wait();

				   // just one thread
#else
  build_some_patches(thread_data[0]);
#endif
};

template <int dim>
typename DoFHandler<dim>::cell_iterator
DataOutRotation<dim>::first_cell ()
{
  return dofs->begin_active ();
};

template <int dim>
typename DoFHandler<dim>::cell_iterator
DataOutRotation<dim>::next_cell (const typename DoFHandler<dim>::cell_iterator &cell)
{
				   // convert the iterator to an
				   // active_iterator and advance
				   // this to the next active cell
  typename DoFHandler<dim>::active_cell_iterator active_cell = cell;
  ++active_cell;
  return active_cell;
};

// explicit instantiations
template class DataOutRotation<deal_II_dimension>;

<|endoftext|>