<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: EnvStack.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-09 13:38:18 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "uno/environment.hxx"

#include "cppu/EnvDcp.hxx"
#include "cppu/Enterable.hxx"

#include "osl/thread.h"
#include "osl/mutex.hxx"

#include <hash_map>

using namespace com::sun::star;

struct SAL_DLLPRIVATE oslThreadIdentifier_equal
{
    bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
};

bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
{
    bool result = s1 == s2;

    return result;
}

struct SAL_DLLPRIVATE oslThreadIdentifier_hash
{
    size_t operator()(oslThreadIdentifier s1) const;
};

size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
{
    return s1;
}

typedef ::std::hash_map<oslThreadIdentifier,
                        uno_Environment *,
                        oslThreadIdentifier_hash,
                        oslThreadIdentifier_equal>  ThreadMap;

static osl::Mutex s_threadMap_mutex;
static ThreadMap  s_threadMap;

static rtl::OUString s_uno_envDcp(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO));

static void s_setCurrent(uno_Environment * pEnv)
{
    oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);

    osl::MutexGuard guard(s_threadMap_mutex);
    if (pEnv)
        s_threadMap[threadId] = pEnv;

    else
    {
        ThreadMap::iterator iEnv = s_threadMap.find(threadId);
        s_threadMap.erase(iEnv);
    }
}

static uno_Environment * s_getCurrent(void)
{
    uno_Environment * pEnv = NULL;

    oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);

    osl::MutexGuard guard(s_threadMap_mutex);
    ThreadMap::iterator iEnv = s_threadMap.find(threadId);
    if(iEnv != s_threadMap.end())
        pEnv = iEnv->second;

    return pEnv;
}

extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
    SAL_THROW_EXTERN_C()
{
    if (*ppEnv)
    {
        (*ppEnv)->release(*ppEnv);
        *ppEnv = NULL;
    }

    rtl::OUString currPurpose;

    uno_Environment * pCurrEnv = s_getCurrent();
    if (pCurrEnv) // no environment means no purpose
        currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);

    if (pTypeName && rtl_uString_getLength(pTypeName))
    {
        rtl::OUString envDcp(pTypeName);
        envDcp += currPurpose;

        uno_getEnvironment(ppEnv, envDcp.pData, NULL);
    }
    else
    {
        if (pCurrEnv)
        {
            *ppEnv = pCurrEnv;
            (*ppEnv)->acquire(*ppEnv);
        }
        else
            uno_getEnvironment(ppEnv, s_uno_envDcp.pData, NULL);

    }
}

static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
{
    sal_Int32 nIndex1 = 0;
    sal_Int32 nIndex2 = 0;
    sal_Int32 sim = 0;

    rtl::OUString token1;
    rtl::OUString token2;

    do
    {
        token1 = str1.getToken(0, ':', nIndex1);
        token2 = str2.getToken(0, ':', nIndex2);

        if (token1.equals(token2))
            sim += token1.getLength() + 1;
    }
    while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));

    rtl::OUString result;

    if (sim)
        result = str1.copy(0, sim - 1);

    return result;
}

static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
{
    int res = 0;

    rtl::OUString nextPurpose;

    rtl::OUString currPurpose;
    if (pCurrEnv)
        currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);

    rtl::OUString targetPurpose;
    if (pTargetEnv)
        targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);

    rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
    if (currPurpose.getLength() > intermPurpose.getLength())
    {
        sal_Int32 idx = currPurpose.lastIndexOf(':');
        nextPurpose = currPurpose.copy(0, idx);

        res = -1;
    }
    else if (intermPurpose.getLength() < targetPurpose.getLength())
    {
        sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
        if (idx == -1)
            nextPurpose = targetPurpose;

        else
            nextPurpose = targetPurpose.copy(0, idx);

        res = 1;
    }

    if (nextPurpose.getLength())
    {
        rtl::OUString next_envDcp(s_uno_envDcp);
        next_envDcp += nextPurpose;

        uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
    }
    else
    {
        if (*ppEnv)
            (*ppEnv)->release(*ppEnv);

        *ppEnv = NULL;
    }

    return res;
}

extern "C" { static void s_pull(va_list param)
{
    uno_EnvCallee * pCallee = va_arg(param, uno_EnvCallee *);
    va_list         xparam  = va_arg(param, va_list);

    pCallee(xparam);
}}

static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list param)
{
    cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
    if (pEnterable)
        pEnterable->callInto(s_pull, pCallee, param);

    else
        pCallee(param);
}

static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
{
    va_list param;

    va_start(param, pCallee);
    s_callInto_v(pEnv, pCallee, param);
    va_end(param);
}

static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list param)
{
    cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
    if (pEnterable)
        pEnterable->callOut_v(pCallee, param);

    else
        pCallee(param);
}

static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
{
    va_list param;

    va_start(param, pCallee);
    s_callOut_v(pEnv, pCallee, param);
    va_end(param);
}

static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list);

extern "C" { static void s_environment_invoke_vv(va_list param)
{
    uno_Environment * pCurrEnv    = va_arg(param, uno_Environment *);
    uno_Environment * pTargetEnv  = va_arg(param, uno_Environment *);
    uno_EnvCallee   * pCallee = va_arg(param, uno_EnvCallee *);
    va_list           xparam  = va_arg(param, va_list);

    s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, xparam);
}}

static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list param)
{
    uno_Environment * pNextEnv = NULL;
    switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
    {
    case -1:
        s_setCurrent(pNextEnv);
        s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, param);
        s_setCurrent(pCurrEnv);
        break;

    case 0: {
        uno_Environment * hld = s_getCurrent();
        s_setCurrent(pCurrEnv);
        pCallee(param);
        s_setCurrent(hld);
    }
        break;

    case 1:
        s_setCurrent(pNextEnv);
        s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, param);
        s_setCurrent(pCurrEnv);
        break;
    }

    if (pNextEnv)
        pNextEnv->release(pNextEnv);
}

extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list param)
    SAL_THROW_EXTERN_C()
{
    s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, param);
}

extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
    SAL_THROW_EXTERN_C()
{
    va_list param;

    va_start(param, pCallee);
    uno_Environment_invoke_v(pEnv, pCallee, param);
    va_end(param);
}

extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
    SAL_THROW_EXTERN_C()
{
    uno_Environment * pNextEnv = NULL;
    uno_Environment * pCurrEnv = s_getCurrent();

    int res;
    while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
    {
        cppu::Enterable * pEnterable;

        switch(res)
        {
        case -1:
            pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
            if (pEnterable)
                pEnterable->leave();
            pCurrEnv->release(pCurrEnv);
            break;

        case 1:
            pNextEnv->acquire(pNextEnv);
            pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
            if (pEnterable)
                pEnterable->enter();
            break;
        }

        s_setCurrent(pNextEnv);
        pCurrEnv = pNextEnv;
    }
}

int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
    SAL_THROW_EXTERN_C()
{
    int result = 1;

    rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
    if (typeName.equals(s_uno_envDcp))
    {
        cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
        if (pEnterable)
            result = pEnterable->isValid((rtl::OUString *)pReason);
    }
    else
    {
        rtl::OUString envDcp(s_uno_envDcp);
        envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);

        uno::Environment env(envDcp);

        result = env.isValid((rtl::OUString *)pReason);
    }

    return result;
}
<commit_msg>#i77422# fix build break for x86_64<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: EnvStack.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-16 15:21:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "uno/environment.hxx"

#include "cppu/EnvDcp.hxx"
#include "cppu/Enterable.hxx"

#include "osl/thread.h"
#include "osl/mutex.hxx"

#include <hash_map>

using namespace com::sun::star;

struct SAL_DLLPRIVATE oslThreadIdentifier_equal
{
    bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const;
};

bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const
{
    bool result = s1 == s2;

    return result;
}

struct SAL_DLLPRIVATE oslThreadIdentifier_hash
{
    size_t operator()(oslThreadIdentifier s1) const;
};

size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const
{
    return s1;
}

typedef ::std::hash_map<oslThreadIdentifier,
                        uno_Environment *,
                        oslThreadIdentifier_hash,
                        oslThreadIdentifier_equal>  ThreadMap;

static osl::Mutex s_threadMap_mutex;
static ThreadMap  s_threadMap;

static rtl::OUString s_uno_envDcp(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO));

static void s_setCurrent(uno_Environment * pEnv)
{
    oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);

    osl::MutexGuard guard(s_threadMap_mutex);
    if (pEnv)
        s_threadMap[threadId] = pEnv;

    else
    {
        ThreadMap::iterator iEnv = s_threadMap.find(threadId);
        s_threadMap.erase(iEnv);
    }
}

static uno_Environment * s_getCurrent(void)
{
    uno_Environment * pEnv = NULL;

    oslThreadIdentifier threadId = osl_getThreadIdentifier(NULL);

    osl::MutexGuard guard(s_threadMap_mutex);
    ThreadMap::iterator iEnv = s_threadMap.find(threadId);
    if(iEnv != s_threadMap.end())
        pEnv = iEnv->second;

    return pEnv;
}

extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName)
    SAL_THROW_EXTERN_C()
{
    if (*ppEnv)
    {
        (*ppEnv)->release(*ppEnv);
        *ppEnv = NULL;
    }

    rtl::OUString currPurpose;

    uno_Environment * pCurrEnv = s_getCurrent();
    if (pCurrEnv) // no environment means no purpose
        currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);

    if (pTypeName && rtl_uString_getLength(pTypeName))
    {
        rtl::OUString envDcp(pTypeName);
        envDcp += currPurpose;

        uno_getEnvironment(ppEnv, envDcp.pData, NULL);
    }
    else
    {
        if (pCurrEnv)
        {
            *ppEnv = pCurrEnv;
            (*ppEnv)->acquire(*ppEnv);
        }
        else
            uno_getEnvironment(ppEnv, s_uno_envDcp.pData, NULL);

    }
}

static rtl::OUString s_getPrefix(rtl::OUString const & str1, rtl::OUString const & str2)
{
    sal_Int32 nIndex1 = 0;
    sal_Int32 nIndex2 = 0;
    sal_Int32 sim = 0;

    rtl::OUString token1;
    rtl::OUString token2;

    do
    {
        token1 = str1.getToken(0, ':', nIndex1);
        token2 = str2.getToken(0, ':', nIndex2);

        if (token1.equals(token2))
            sim += token1.getLength() + 1;
    }
    while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1.equals(token2));

    rtl::OUString result;

    if (sim)
        result = str1.copy(0, sim - 1);

    return result;
}

static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv)
{
    int res = 0;

    rtl::OUString nextPurpose;

    rtl::OUString currPurpose;
    if (pCurrEnv)
        currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName);

    rtl::OUString targetPurpose;
    if (pTargetEnv)
        targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName);

    rtl::OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose));
    if (currPurpose.getLength() > intermPurpose.getLength())
    {
        sal_Int32 idx = currPurpose.lastIndexOf(':');
        nextPurpose = currPurpose.copy(0, idx);

        res = -1;
    }
    else if (intermPurpose.getLength() < targetPurpose.getLength())
    {
        sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1);
        if (idx == -1)
            nextPurpose = targetPurpose;

        else
            nextPurpose = targetPurpose.copy(0, idx);

        res = 1;
    }

    if (nextPurpose.getLength())
    {
        rtl::OUString next_envDcp(s_uno_envDcp);
        next_envDcp += nextPurpose;

        uno_getEnvironment(ppEnv, next_envDcp.pData, NULL);
    }
    else
    {
        if (*ppEnv)
            (*ppEnv)->release(*ppEnv);

        *ppEnv = NULL;
    }

    return res;
}

extern "C" { static void s_pull(va_list param)
{
    uno_EnvCallee * pCallee = va_arg(param, uno_EnvCallee *);
       va_list       * xparam  = va_arg(param, va_list *);

       pCallee(*xparam);
}}

static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list param)
{
    cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
    if (pEnterable)
               pEnterable->callInto(s_pull, pCallee, &param);

    else
        pCallee(param);
}

static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
{
    va_list param;

    va_start(param, pCallee);
    s_callInto_v(pEnv, pCallee, param);
    va_end(param);
}

static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list param)
{
    cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
    if (pEnterable)
        pEnterable->callOut_v(pCallee, param);

    else
        pCallee(param);
}

static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
{
    va_list param;

    va_start(param, pCallee);
    s_callOut_v(pEnv, pCallee, param);
    va_end(param);
}

static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list);

extern "C" { static void s_environment_invoke_vv(va_list param)
{
    uno_Environment * pCurrEnv    = va_arg(param, uno_Environment *);
    uno_Environment * pTargetEnv  = va_arg(param, uno_Environment *);
    uno_EnvCallee   * pCallee = va_arg(param, uno_EnvCallee *);
       va_list         *  xparam  = va_arg(param, va_list *);

       s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, *xparam);
}}

static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list param)
{
    uno_Environment * pNextEnv = NULL;
    switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv))
    {
    case -1:
        s_setCurrent(pNextEnv);
               s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, &param);
        s_setCurrent(pCurrEnv);
        break;

    case 0: {
        uno_Environment * hld = s_getCurrent();
        s_setCurrent(pCurrEnv);
        pCallee(param);
        s_setCurrent(hld);
    }
        break;

    case 1:
        s_setCurrent(pNextEnv);
               s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, &param);
        s_setCurrent(pCurrEnv);
        break;
    }

    if (pNextEnv)
        pNextEnv->release(pNextEnv);
}

extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list param)
    SAL_THROW_EXTERN_C()
{
    s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, param);
}

extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...)
    SAL_THROW_EXTERN_C()
{
    va_list param;

    va_start(param, pCallee);
    uno_Environment_invoke_v(pEnv, pCallee, param);
    va_end(param);
}

extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv)
    SAL_THROW_EXTERN_C()
{
    uno_Environment * pNextEnv = NULL;
    uno_Environment * pCurrEnv = s_getCurrent();

    int res;
    while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0)
    {
        cppu::Enterable * pEnterable;

        switch(res)
        {
        case -1:
            pEnterable = reinterpret_cast<cppu::Enterable *>(pCurrEnv->pReserved);
            if (pEnterable)
                pEnterable->leave();
            pCurrEnv->release(pCurrEnv);
            break;

        case 1:
            pNextEnv->acquire(pNextEnv);
            pEnterable = reinterpret_cast<cppu::Enterable *>(pNextEnv->pReserved);
            if (pEnterable)
                pEnterable->enter();
            break;
        }

        s_setCurrent(pNextEnv);
        pCurrEnv = pNextEnv;
    }
}

int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason)
    SAL_THROW_EXTERN_C()
{
    int result = 1;

    rtl::OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName));
    if (typeName.equals(s_uno_envDcp))
    {
        cppu::Enterable * pEnterable = reinterpret_cast<cppu::Enterable *>(pEnv->pReserved);
        if (pEnterable)
            result = pEnterable->isValid((rtl::OUString *)pReason);
    }
    else
    {
        rtl::OUString envDcp(s_uno_envDcp);
        envDcp += cppu::EnvDcp::getPurpose(pEnv->pTypeName);

        uno::Environment env(envDcp);

        result = env.isValid((rtl::OUString *)pReason);
    }

    return result;
}
<|endoftext|>


<commit_before>/* Copyright 2019 Stanford University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <unistd.h>

#include <legion.h>
#include <realm/cmdline.h>
#include <mappers/default_mapper.h>

#include <Kokkos_Core.hpp>
#ifdef USE_KOKKOS_KERNELS
#include <KokkosBlas.hpp>
#endif

#include <typeinfo>

using namespace Legion;

Logger log_app("app");

enum {
  TOP_LEVEL_TASK_ID,
  SAXPY_TASK_ID,
  SDOT_TASK_ID
};

enum {
  FID_X = 100,
  FID_Y,
};

struct SaxpyTaskArgs {
  float alpha;
};

typedef FieldAccessor<READ_ONLY, float, 1, coord_t,
		      Realm::AffineAccessor<float, 1, coord_t> > AccessorRO;
typedef FieldAccessor<READ_WRITE, float, 1, coord_t,
		      Realm::AffineAccessor<float, 1, coord_t> > AccessorRW;

// we'll do saxpy with a functor and sdot below with a lambda
template <class execution_space>
class SaxpyFunctor {
public:
  float alpha;
  Kokkos::View<const float *, execution_space> x;
  Kokkos::View<float *, execution_space> y;

  SaxpyFunctor(float _alpha,
	       Kokkos::View<const float *, execution_space> _x,
	       Kokkos::View<float *, execution_space> _y)
    : alpha(_alpha), x(_x), y(_y) {}

  KOKKOS_FUNCTION void operator()(int i) const
  {
    y(i) += alpha * x(i);
  }
};

// we have to wrap our tasks in classes so that we can use them as template
//  template parameters below (function templates cannot be template template
//  parameters)
template <typename execution_space>
class SaxpyTask {
public:
  static void task_body(const Task *task,
			const std::vector<PhysicalRegion> &regions,
			Context ctx, Runtime *runtime)
  {
    printf("kokkos(%s) saxpy task on processor " IDFMT ", kind %d\n",
           typeid(execution_space).name(),
           runtime->get_executing_processor(ctx).id,
           runtime->get_executing_processor(ctx).kind());
    const SaxpyTaskArgs& args = *reinterpret_cast<const SaxpyTaskArgs *>(task->args);
    AccessorRO acc_x(regions[0], FID_X);
    AccessorRW acc_y(regions[1], FID_Y);

    Rect<1> subspace = runtime->get_index_space_domain(ctx,
						       task->regions[0].region.get_index_space());

    Kokkos::View<const float *,
		 typename execution_space::memory_space> x = acc_x.accessor;
    Kokkos::View<float *,
		 typename execution_space::memory_space> y = acc_y.accessor;
#ifdef USE_KOKKOS_KERNELS
    // only do half the child tasks with kokkos-kernels because we want to
    //  test application-supplied kernels too
    if((task->index_point[0] % 2) == 0) {
      KokkosBlas::axpy(args.alpha,
		       Kokkos::subview(x, std::make_pair(subspace.lo.x,
							 subspace.hi.x + 1)),
		       Kokkos::subview(y, std::make_pair(subspace.lo.x,
							 subspace.hi.x + 1)));
    } else
#endif
    {
      Kokkos::RangePolicy<execution_space> range(runtime->get_executing_processor(ctx).kokkos_work_space(),
						 subspace.lo.x,
						 subspace.hi.x + 1);
      Kokkos::parallel_for(range,
			   SaxpyFunctor<execution_space>(args.alpha, x, y));
    }
  }
};

template <typename execution_space>
class SdotTask {
public:
  static float task_body(const Task *task,
			 const std::vector<PhysicalRegion> &regions,
			 Context ctx, Runtime *runtime)
  {
    printf("kokkos(%s) sdot task on processor " IDFMT ", kind %d\n",
           typeid(execution_space).name(),
           runtime->get_executing_processor(ctx).id,
           runtime->get_executing_processor(ctx).kind());
    Rect<1> subspace = runtime->get_index_space_domain(ctx,
						       task->regions[0].region.get_index_space());

    AccessorRO acc_x(regions[0], task->regions[0].instance_fields[0]);
    AccessorRO acc_y(regions[1], task->regions[1].instance_fields[0]);

    Kokkos::View<const float *,
		 typename execution_space::memory_space> x = acc_x.accessor;
    Kokkos::View<const float *,
		 typename execution_space::memory_space> y = acc_y.accessor;
#ifdef USE_KOKKOS_KERNELS
    // only do half the child tasks with kokkos-kernels because we want to
    //  test application-supplied kernels too
    if((task->index_point[0] % 2) == 0) {
      return KokkosBlas::dot(Kokkos::subview(x, std::make_pair(subspace.lo.x,
							       subspace.hi.x + 1)),
			     Kokkos::subview(y, std::make_pair(subspace.lo.x,
							       subspace.hi.x + 1))
			     );
    }
#endif
    Kokkos::RangePolicy<execution_space> range(runtime->get_executing_processor(ctx).kokkos_work_space(),
					       subspace.lo.x,
					       subspace.hi.x + 1);
    float sum = 0.0f;
    // Kokkos does not support CUDA lambdas by default - check that they
    //  are present
#if defined(KOKKOS_ENABLE_CUDA) && !defined(KOKKOS_ENABLE_CUDA_LAMBDA)
    #error Kokkos built without --with-cuda_options=enable_lambda !
#endif
    Kokkos::parallel_reduce(range,
			    KOKKOS_LAMBDA ( int j, float &update ) {
			      update += x(j) * y(j);
			    }, sum);
    return sum;
  }
};

void top_level_task(const Task *task,
                    const std::vector<PhysicalRegion> &regions,
                    Context ctx, Runtime *runtime)
{
  size_t num_elements = 32768;
  size_t num_pieces = 4;

  const InputArgs &command_args = Runtime::get_input_args();

  bool ok = Realm::CommandLineParser()
    .add_option_int("-n", num_elements)
    .add_option_int("-p", num_pieces)
    .parse_command_line(command_args.argc, (const char **)command_args.argv);

  if(!ok) {
    log_app.fatal() << "error parsing command line arguments";
    exit(1);
  }

  Rect<1> r_top = Rect<1>(0, num_elements - 1);
  IndexSpace is_top = runtime->create_index_space(ctx, r_top);

  IndexSpace launch_space = runtime->create_index_space(ctx,
							Rect<1>(1, num_pieces));
  IndexPartition ip_dist = runtime->create_equal_partition(ctx, is_top,
							   launch_space);

  FieldSpace fs = runtime->create_field_space(ctx);
  {
    FieldAllocator fa = runtime->create_field_allocator(ctx, fs);
    fa.allocate_field(sizeof(float), FID_X);
    fa.allocate_field(sizeof(float), FID_Y);
  }

  LogicalRegion lr = runtime->create_logical_region(ctx, is_top, fs);
  LogicalPartition lp_dist = runtime->get_logical_partition(ctx, lr, ip_dist);

  // initial values for x and y
  runtime->fill_field<float>(ctx, lr, lr, FID_X, 2.0f);
  runtime->fill_field<float>(ctx, lr, lr, FID_Y, 3.0f);

  // index launch to compute saxpy on chunks of vector in parallel
  {
    SaxpyTaskArgs args;
    args.alpha = 0.5f;

    IndexTaskLauncher itl(SAXPY_TASK_ID, launch_space,
			  TaskArgument(&args, sizeof(args)),
			  ArgumentMap());
    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_ONLY, EXCLUSIVE, lr)
			       .add_field(FID_X));
    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_WRITE, EXCLUSIVE, lr)
			       .add_field(FID_Y));
    runtime->execute_index_space(ctx, itl);
  }

  // second index launch to compute a dot product on the result
  Future f_sum;
  {
    IndexTaskLauncher itl(SDOT_TASK_ID, launch_space,
			  TaskArgument(),
			  ArgumentMap());

    // prefer CPU variants here so that we try mixing and matching CPU
    //  and GPU tasks when both are available
    itl.tag |= Legion::Mapping::DefaultMapper::PREFER_CPU_VARIANT;

    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_ONLY, EXCLUSIVE, lr)
			       .add_field(FID_X));
    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_ONLY, EXCLUSIVE, lr)
			       .add_field(FID_Y));
    f_sum = runtime->execute_index_space(ctx, itl,
					 LEGION_REDOP_SUM_FLOAT32);
  }
  float act_sum = f_sum.get_result<float>(true /*silence_warnings*/);
  float exp_sum = num_elements * 2.0 * (3.0 + 0.5 * 2.0);

  printf("got %g, exp %g\n", act_sum, exp_sum);

  // tear stuff down
  runtime->destroy_logical_region(ctx, lr);
  runtime->destroy_index_partition(ctx, ip_dist);
  runtime->destroy_index_space(ctx, is_top);
  runtime->destroy_field_space(ctx, fs);
}

template <template<typename> class PORTABLE_KOKKOS_TASK>
void preregister_kokkos_task(TaskID task_id, const char *name)
{
#ifdef KOKKOS_ENABLE_SERIAL
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<
      PORTABLE_KOKKOS_TASK<Kokkos::Serial>::task_body >(registrar, name);
  }
#endif

  // register an openmp version, if available
#ifdef KOKKOS_ENABLE_OPENMP
  {
    TaskVariantRegistrar registrar(task_id, name);
#ifdef REALM_USE_OPENMP
    registrar.add_constraint(ProcessorConstraint(Processor::OMP_PROC));
#else
    // if realm is not openmp-aware, put this on normal cpu cores and
    //  hope for the best
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
#endif
    Runtime::preregister_task_variant<
      PORTABLE_KOKKOS_TASK<Kokkos::OpenMP>::task_body >(registrar, name);
  }
#endif

#if defined(KOKKOS_ENABLE_CUDA) and defined(REALM_USE_CUDA)
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::TOC_PROC));
    Runtime::preregister_task_variant<
      PORTABLE_KOKKOS_TASK<Kokkos::Cuda>::task_body >(registrar, name);
  }
#endif
}

// for tasks with a non-void return value
template <typename RV, template<typename> class PORTABLE_KOKKOS_TASK>
void preregister_kokkos_task(TaskID task_id, const char *name)
{
#ifdef KOKKOS_ENABLE_SERIAL
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<
      RV, PORTABLE_KOKKOS_TASK<Kokkos::Serial>::task_body >(registrar, name);
  }
#endif

  // register an openmp version, if available
#ifdef KOKKOS_ENABLE_OPENMP
  {
    TaskVariantRegistrar registrar(task_id, name);
#ifdef REALM_USE_OPENMP
    registrar.add_constraint(ProcessorConstraint(Processor::OMP_PROC));
#else
    // if realm is not openmp-aware, put this on normal cpu cores and
    //  hope for the best
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
#endif
    Runtime::preregister_task_variant<
      RV, PORTABLE_KOKKOS_TASK<Kokkos::OpenMP>::task_body >(registrar, name);
  }
#endif

#if defined(KOKKOS_ENABLE_CUDA) and defined(REALM_USE_CUDA)
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::TOC_PROC));
    Runtime::preregister_task_variant<
      RV, PORTABLE_KOKKOS_TASK<Kokkos::Cuda>::task_body >(registrar, name);
  }
#endif
}

int main(int argc, char **argv)
{
  Runtime::set_top_level_task_id(TOP_LEVEL_TASK_ID);

  {
    TaskVariantRegistrar registrar(TOP_LEVEL_TASK_ID, "top_level");
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<top_level_task>(registrar, "top_level");
  }

  preregister_kokkos_task<SaxpyTask>(SAXPY_TASK_ID, "saxpy");
  preregister_kokkos_task<float, SdotTask>(SDOT_TASK_ID, "sdot");

  return Runtime::start(argc, argv);
}

<commit_msg>examples: work around over-zealous kokkos-kernels fencing<commit_after>/* Copyright 2019 Stanford University
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <unistd.h>

#include <legion.h>
#include <realm/cmdline.h>
#include <mappers/default_mapper.h>

#include <Kokkos_Core.hpp>
#ifdef USE_KOKKOS_KERNELS
#include <KokkosBlas.hpp>
#endif

#include <typeinfo>

using namespace Legion;

Logger log_app("app");

enum {
  TOP_LEVEL_TASK_ID,
  SAXPY_TASK_ID,
  SDOT_TASK_ID
};

enum {
  FID_X = 100,
  FID_Y,
};

struct SaxpyTaskArgs {
  float alpha;
};

typedef FieldAccessor<READ_ONLY, float, 1, coord_t,
		      Realm::AffineAccessor<float, 1, coord_t> > AccessorRO;
typedef FieldAccessor<READ_WRITE, float, 1, coord_t,
		      Realm::AffineAccessor<float, 1, coord_t> > AccessorRW;

// we'll do saxpy with a functor and sdot below with a lambda
template <class execution_space>
class SaxpyFunctor {
public:
  float alpha;
  Kokkos::View<const float *, execution_space> x;
  Kokkos::View<float *, execution_space> y;

  SaxpyFunctor(float _alpha,
	       Kokkos::View<const float *, execution_space> _x,
	       Kokkos::View<float *, execution_space> _y)
    : alpha(_alpha), x(_x), y(_y) {}

  KOKKOS_FUNCTION void operator()(int i) const
  {
    y(i) += alpha * x(i);
  }
};

// we have to wrap our tasks in classes so that we can use them as template
//  template parameters below (function templates cannot be template template
//  parameters)
template <typename execution_space>
class SaxpyTask {
public:
  static void task_body(const Task *task,
			const std::vector<PhysicalRegion> &regions,
			Context ctx, Runtime *runtime)
  {
    printf("kokkos(%s) saxpy task on processor " IDFMT ", kind %d\n",
           typeid(execution_space).name(),
           runtime->get_executing_processor(ctx).id,
           runtime->get_executing_processor(ctx).kind());
    const SaxpyTaskArgs& args = *reinterpret_cast<const SaxpyTaskArgs *>(task->args);
    AccessorRO acc_x(regions[0], FID_X);
    AccessorRW acc_y(regions[1], FID_Y);

    Rect<1> subspace = runtime->get_index_space_domain(ctx,
						       task->regions[0].region.get_index_space());

    Kokkos::View<const float *,
		 typename execution_space::memory_space> x = acc_x.accessor;
    Kokkos::View<float *,
		 typename execution_space::memory_space> y = acc_y.accessor;
#ifdef USE_KOKKOS_KERNELS
    // only do half the child tasks with kokkos-kernels because we want to
    //  test application-supplied kernels too
    if((task->index_point[0] % 2) == 0) {
      KokkosBlas::axpy(args.alpha,
		       Kokkos::subview(x, std::make_pair(subspace.lo.x,
							 subspace.hi.x + 1)),
		       Kokkos::subview(y, std::make_pair(subspace.lo.x,
							 subspace.hi.x + 1)));
    } else
#endif
    {
      Kokkos::RangePolicy<execution_space> range(runtime->get_executing_processor(ctx).kokkos_work_space(),
						 subspace.lo.x,
						 subspace.hi.x + 1);
      Kokkos::parallel_for(range,
			   SaxpyFunctor<execution_space>(args.alpha, x, y));
    }
  }
};

template <typename execution_space>
class SdotTask {
public:
  static float task_body(const Task *task,
			 const std::vector<PhysicalRegion> &regions,
			 Context ctx, Runtime *runtime)
  {
    printf("kokkos(%s) sdot task on processor " IDFMT ", kind %d\n",
           typeid(execution_space).name(),
           runtime->get_executing_processor(ctx).id,
           runtime->get_executing_processor(ctx).kind());
    Rect<1> subspace = runtime->get_index_space_domain(ctx,
						       task->regions[0].region.get_index_space());

    AccessorRO acc_x(regions[0], task->regions[0].instance_fields[0]);
    AccessorRO acc_y(regions[1], task->regions[1].instance_fields[0]);

    Kokkos::View<const float *,
		 typename execution_space::memory_space> x = acc_x.accessor;
    Kokkos::View<const float *,
		 typename execution_space::memory_space> y = acc_y.accessor;
#ifdef USE_KOKKOS_KERNELS
    // only do half the child tasks with kokkos-kernels because we want to
    //  test application-supplied kernels too
    if((task->index_point[0] % 2) == 0) {
      // the KokkosBlas::dot implementation that returns a float directly
      //  performs a fence on all execution spaces, which is not permitted by
      //  default in Legion - see:
      //     https://github.com/kokkos/kokkos-kernels/issues/757
      //
      // instead, use the variant that fills a (managed) view and explicitly
      //  copy back to a host mirror
      float result_host;
      {
	Kokkos::View<float,
		     typename execution_space::memory_space> result("result");
	KokkosBlas::dot(result,
			Kokkos::subview(x, std::make_pair(subspace.lo.x,
							  subspace.hi.x + 1)),
			Kokkos::subview(y, std::make_pair(subspace.lo.x,
							  subspace.hi.x + 1))
			);
	// can't use `kokkos_work_space` here because KokkosBlas::dot didn't
	Kokkos::deep_copy(execution_space(), result_host, result);
      }
      execution_space().fence();
      return result_host;
    }
#endif
    Kokkos::RangePolicy<execution_space> range(runtime->get_executing_processor(ctx).kokkos_work_space(),
					       subspace.lo.x,
					       subspace.hi.x + 1);
    float sum = 0.0f;
    // Kokkos does not support CUDA lambdas by default - check that they
    //  are present
#if defined(KOKKOS_ENABLE_CUDA) && !defined(KOKKOS_ENABLE_CUDA_LAMBDA)
    #error Kokkos built without --with-cuda_options=enable_lambda !
#endif
    Kokkos::parallel_reduce(range,
			    KOKKOS_LAMBDA ( int j, float &update ) {
			      update += x(j) * y(j);
			    }, sum);
    return sum;
  }
};

void top_level_task(const Task *task,
                    const std::vector<PhysicalRegion> &regions,
                    Context ctx, Runtime *runtime)
{
  size_t num_elements = 32768;
  size_t num_pieces = 4;
  int mixed_processors = 1;

  const InputArgs &command_args = Runtime::get_input_args();

  bool ok = Realm::CommandLineParser()
    .add_option_int("-n", num_elements)
    .add_option_int("-p", num_pieces)
    .add_option_int("-mixed", mixed_processors)
    .parse_command_line(command_args.argc, (const char **)command_args.argv);

  if(!ok) {
    log_app.fatal() << "error parsing command line arguments";
    exit(1);
  }

  Rect<1> r_top = Rect<1>(0, num_elements - 1);
  IndexSpace is_top = runtime->create_index_space(ctx, r_top);

  IndexSpace launch_space = runtime->create_index_space(ctx,
							Rect<1>(1, num_pieces));
  IndexPartition ip_dist = runtime->create_equal_partition(ctx, is_top,
							   launch_space);

  FieldSpace fs = runtime->create_field_space(ctx);
  {
    FieldAllocator fa = runtime->create_field_allocator(ctx, fs);
    fa.allocate_field(sizeof(float), FID_X);
    fa.allocate_field(sizeof(float), FID_Y);
  }

  LogicalRegion lr = runtime->create_logical_region(ctx, is_top, fs);
  LogicalPartition lp_dist = runtime->get_logical_partition(ctx, lr, ip_dist);

  // initial values for x and y
  runtime->fill_field<float>(ctx, lr, lr, FID_X, 2.0f);
  runtime->fill_field<float>(ctx, lr, lr, FID_Y, 3.0f);

  // index launch to compute saxpy on chunks of vector in parallel
  {
    SaxpyTaskArgs args;
    args.alpha = 0.5f;

    IndexTaskLauncher itl(SAXPY_TASK_ID, launch_space,
			  TaskArgument(&args, sizeof(args)),
			  ArgumentMap());
    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_ONLY, EXCLUSIVE, lr)
			       .add_field(FID_X));
    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_WRITE, EXCLUSIVE, lr)
			       .add_field(FID_Y));
    runtime->execute_index_space(ctx, itl);
  }

  // second index launch to compute a dot product on the result
  Future f_sum;
  {
    IndexTaskLauncher itl(SDOT_TASK_ID, launch_space,
			  TaskArgument(),
			  ArgumentMap());

    // prefer CPU variants here so that we try mixing and matching CPU
    //  and GPU tasks when both are available
    if(mixed_processors)
      itl.tag |= Legion::Mapping::DefaultMapper::PREFER_CPU_VARIANT;

    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_ONLY, EXCLUSIVE, lr)
			       .add_field(FID_X));
    itl.add_region_requirement(RegionRequirement(lp_dist,
						 0 /*IDENTITY PROJECTION*/,
						 READ_ONLY, EXCLUSIVE, lr)
			       .add_field(FID_Y));
    f_sum = runtime->execute_index_space(ctx, itl,
					 LEGION_REDOP_SUM_FLOAT32);
  }
  float act_sum = f_sum.get_result<float>(true /*silence_warnings*/);
  float exp_sum = num_elements * 2.0 * (3.0 + 0.5 * 2.0);

  printf("got %g, exp %g\n", act_sum, exp_sum);

  // tear stuff down
  runtime->destroy_logical_region(ctx, lr);
  runtime->destroy_index_partition(ctx, ip_dist);
  runtime->destroy_index_space(ctx, is_top);
  runtime->destroy_field_space(ctx, fs);
}

template <template<typename> class PORTABLE_KOKKOS_TASK>
void preregister_kokkos_task(TaskID task_id, const char *name)
{
#ifdef KOKKOS_ENABLE_SERIAL
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<
      PORTABLE_KOKKOS_TASK<Kokkos::Serial>::task_body >(registrar, name);
  }
#endif

  // register an openmp version, if available
#ifdef KOKKOS_ENABLE_OPENMP
  {
    TaskVariantRegistrar registrar(task_id, name);
#ifdef REALM_USE_OPENMP
    registrar.add_constraint(ProcessorConstraint(Processor::OMP_PROC));
#else
    // if realm is not openmp-aware, put this on normal cpu cores and
    //  hope for the best
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
#endif
    Runtime::preregister_task_variant<
      PORTABLE_KOKKOS_TASK<Kokkos::OpenMP>::task_body >(registrar, name);
  }
#endif

#if defined(KOKKOS_ENABLE_CUDA) and defined(REALM_USE_CUDA)
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::TOC_PROC));
    Runtime::preregister_task_variant<
      PORTABLE_KOKKOS_TASK<Kokkos::Cuda>::task_body >(registrar, name);
  }
#endif
}

// for tasks with a non-void return value
template <typename RV, template<typename> class PORTABLE_KOKKOS_TASK>
void preregister_kokkos_task(TaskID task_id, const char *name)
{
#ifdef KOKKOS_ENABLE_SERIAL
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<
      RV, PORTABLE_KOKKOS_TASK<Kokkos::Serial>::task_body >(registrar, name);
  }
#endif

  // register an openmp version, if available
#ifdef KOKKOS_ENABLE_OPENMP
  {
    TaskVariantRegistrar registrar(task_id, name);
#ifdef REALM_USE_OPENMP
    registrar.add_constraint(ProcessorConstraint(Processor::OMP_PROC));
#else
    // if realm is not openmp-aware, put this on normal cpu cores and
    //  hope for the best
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
#endif
    Runtime::preregister_task_variant<
      RV, PORTABLE_KOKKOS_TASK<Kokkos::OpenMP>::task_body >(registrar, name);
  }
#endif

#if defined(KOKKOS_ENABLE_CUDA) and defined(REALM_USE_CUDA)
  // register a serial version on the CPU
  {
    TaskVariantRegistrar registrar(task_id, name);
    registrar.add_constraint(ProcessorConstraint(Processor::TOC_PROC));
    Runtime::preregister_task_variant<
      RV, PORTABLE_KOKKOS_TASK<Kokkos::Cuda>::task_body >(registrar, name);
  }
#endif
}

int main(int argc, char **argv)
{
  Runtime::set_top_level_task_id(TOP_LEVEL_TASK_ID);

  {
    TaskVariantRegistrar registrar(TOP_LEVEL_TASK_ID, "top_level");
    registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<top_level_task>(registrar, "top_level");
  }

  preregister_kokkos_task<SaxpyTask>(SAXPY_TASK_ID, "saxpy");
  preregister_kokkos_task<float, SdotTask>(SDOT_TASK_ID, "sdot");

  return Runtime::start(argc, argv);
}

<|endoftext|>


<commit_before>#include "ics3/ics"

#include<iostream>
#include<cassert>
#include<thread>
#include<chrono>

void testAngle();
void testBaudrate();
void testEepParam();
void testID();
void testParameter();
void testICS3();
void testIcsMove(ics::ICS3&, const ics::ID&);
void testIcsParam(ics::ICS3&, const ics::ID&);
void testIcsEepRom(ics::ICS3&, const ics::ID&);

template<typename Iter>
constexpr void dump(Iter&& begin, Iter&& end) noexcept;

int main() {
  testAngle();
  testBaudrate();
  testEepParam();
  testID();
  testParameter();
  testICS3();
  return 0;
}

void testAngle() {
  std::cout << std::endl << "angle test section" << std::endl;
  // constexpr test
  constexpr auto defDeg = ics::Angle::newDegree();
  constexpr auto defRad = ics::Angle::newRadian();
  static_assert(defDeg == 0, "Angle default cast error");
  static_assert(defRad.get() == 0, "Angle default get() error");
  static_assert(defDeg.getRaw() == 7500, "Angle default must is 7500");
  static_assert(defDeg.getRaw() == defRad.getRaw(), "Angle have different default");
  constexpr auto degree1 = ics::Angle::newDegree(90);
  constexpr auto radian1 = ics::Angle::newRadian(M_PI / 2);
  static_assert(degree1.getRaw() == radian1.getRaw(), "difference: 90 deg <-> pi/2 rad");
  constexpr auto degree2 = ics::Angle::newDegree(30);
  constexpr auto radian2 = ics::Angle::newRadian(M_PI / 6);
  static_assert(degree2.getRaw() == radian2.getRaw(), "difference: 30 deg <-> pi/6 rad");
  try {
    ics::Angle::newDegree(136);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }

  // runtime test
  auto degree = ics::Angle::newDegree(0);
  auto radian = ics::Angle::newRadian(0);
  assert(degree.getRaw() == radian.getRaw());
  degree.set(90);
  radian.set(M_PI / 2);
  assert(degree.getRaw() == radian.getRaw());
  degree.set(-60);
  radian.set(-M_PI / 3);
  assert(degree.getRaw() == radian.getRaw());
  try {
    degree.set(150);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
  try {
    radian.set(M_PI);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testBaudrate() {
  std::cout << std::endl << "Baudrate test section" << std::endl;
  // constexpr test
  constexpr auto baudrate115200 = ics::Baudrate::RATE115200();
  static_assert(baudrate115200 == 10, "Baudrate: not equal B115200");
  static_assert(baudrate115200.get() == 10, "Baudrate: romdata error");
  static_assert(baudrate115200.getSpeed() == B115200, "Baudrate: getSpeed method error");
}

void testEepParam() {
  std::cout << std::endl << "EepParam test section" << std::endl;
  // constexpr test
  constexpr auto current = ics::EepParam::current();
  static_assert(63 == current.get(), "current error");
  constexpr auto stretch = ics::EepParam::stretch(244);
  static_assert(244 == stretch.get(), "strech error");
  try {
    ics::EepParam::flag(10);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }

  // runtime test
  auto speed = ics::EepParam::speed();
  assert(127 == speed.get());
  speed.set(100);
  assert(100 == speed.get());
  try {
    speed.set(200);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testID() {
  std::cout << std::endl << "ID test section" << std::endl;
  constexpr ics::ID id {0};
  static_assert(id == 0, "id 0 error");
  static_assert(id.get() == 0, "id 0 error by get");
  constexpr ics::ID id31 {31};
  static_assert(id31 == 31, "id 31 error");
  static_assert(id31.get() == 31, "id 31 error by get");
  try {
    ics::ID id32 {32}; // if constexpr, compile error
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
  try {
    ics::ID error {static_cast<uint8_t>(-1)}; // if constexpr, compile error
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testParameter() {
  std::cout << std::endl << "parameter test section" << std::endl;
  // constexpr test
  constexpr auto stretch = ics::Parameter::stretch();
  static_assert(30 == stretch.get(), "stretch error");
  static_assert(30 == stretch, "stretch error by cast");
  static_assert(0x01 == stretch.getSubcommand(), "stretch error by subcommand");
  constexpr auto speed = ics::Parameter::speed(100);
  static_assert(100 == speed.get(), "speed error");
  static_assert(100 == speed, "speed error by cast");
  static_assert(0x02 == speed.getSubcommand(), "speed error by subcommand");
  try {
    ics::Parameter::temperature(0);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }

  // runtime test
  auto current = ics::Parameter::current();
  assert(63 == current.get());
  assert(0x03 == current.getSubcommand());
  current.set(30);
  assert(30 == current);
  current = 10;
  assert(10 == current);
  try {
    current.set(70);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
  try {
    current = 64;
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testICS3() {
  std::cout << std::endl << "ICS3 test section" << std::endl;
  constexpr const char*const path = "/dev/ttyUSB0";
  constexpr auto baudrate = ics::Baudrate::RATE115200();
  constexpr ics::ID id {2};
  try {
    ics::ICS3 ics {path, baudrate};
    testIcsMove(ics, id);
    testIcsParam(ics, id);
    testIcsEepRom(ics, id);
  } catch (std::runtime_error& e) {
    std::cout << e.what() << std::endl;
  }
}

void testIcsMove(ics::ICS3& ics, const ics::ID& id) {
  std::cout << "ICS3 'move' and 'free' method test section"  << std::endl;
  auto degree = ics::Angle::newDegree();
  std::cout << "move to " << degree << "[deg]" << std::endl;
  auto nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  degree = 50;
  std::cout << "move to " << degree << "[deg]" << std::endl;
  nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  degree = -50;
  std::cout << "move to " << degree << "[deg]" << std::endl;
  nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  degree = 0;
  std::cout << "move to " << degree << "[deg]" << std::endl;
  nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  std::cout << "free torque" << std::endl;
  nowPos = ics.free(id);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
}

void testIcsParam(ics::ICS3& ics, const ics::ID& id) {
  std::cout << "ICS3 'get' and 'set' method test section"  << std::endl;
  auto defaultStretch = ics.get(id, ics::Parameter::stretch());
  std::cout << "default stretch is " << static_cast<int>(defaultStretch) << std::endl;
  constexpr uint8_t writeNumber {29};
  ics.set(id, ics::Parameter::stretch(writeNumber));
  auto newStretch = ics.get(id, defaultStretch);
  ics.set(id, defaultStretch); // before checking, restore data.
  assert(newStretch == writeNumber);
  assert(defaultStretch == ics.get(id, defaultStretch));
}

void testIcsEepRom(ics::ICS3& ics, const ics::ID& id) {
  std::cout << "ics 'getRom' and 'setRom' test section" << std::endl;
  auto rom = ics.getRom(id);
  auto defaultStretch = rom.get(ics::EepParam::stretch());
  std::cout << "default stretch is " << defaultStretch << std::endl;
  auto setRom = rom;
  constexpr uint16_t writeNumber {62};
  setRom.set(ics::EepParam::stretch(writeNumber));
  ics.setRom(id, setRom);
  auto newRom = ics.getRom(id);
  ics.setRom(id, rom); // before checking, restore data.
  assert(newRom.get(defaultStretch) == writeNumber);
  auto lastRom = ics.getRom(id);
  assert(defaultStretch == lastRom.get(defaultStretch));
}

template<typename Iter>
constexpr void dump(Iter&& begin, Iter&& end) noexcept {
  while (begin != end) std::cout << static_cast<int>(*begin++) << ", ";
  std::cout << std::endl;
}
<commit_msg>Update testcode for eepparam exception<commit_after>#include "ics3/ics"

#include<iostream>
#include<cassert>
#include<thread>
#include<chrono>

void testAngle();
void testBaudrate();
void testEepParam();
void testID();
void testParameter();
void testICS3();
void testIcsMove(ics::ICS3&, const ics::ID&);
void testIcsParam(ics::ICS3&, const ics::ID&);
void testIcsEepRom(ics::ICS3&, const ics::ID&);

template<typename Iter>
constexpr void dump(Iter&& begin, Iter&& end) noexcept;

int main() {
  testAngle();
  testBaudrate();
  testEepParam();
  testID();
  testParameter();
  testICS3();
  return 0;
}

void testAngle() {
  std::cout << std::endl << "angle test section" << std::endl;
  // constexpr test
  constexpr auto defDeg = ics::Angle::newDegree();
  constexpr auto defRad = ics::Angle::newRadian();
  static_assert(defDeg == 0, "Angle default cast error");
  static_assert(defRad.get() == 0, "Angle default get() error");
  static_assert(defDeg.getRaw() == 7500, "Angle default must is 7500");
  static_assert(defDeg.getRaw() == defRad.getRaw(), "Angle have different default");
  constexpr auto degree1 = ics::Angle::newDegree(90);
  constexpr auto radian1 = ics::Angle::newRadian(M_PI / 2);
  static_assert(degree1.getRaw() == radian1.getRaw(), "difference: 90 deg <-> pi/2 rad");
  constexpr auto degree2 = ics::Angle::newDegree(30);
  constexpr auto radian2 = ics::Angle::newRadian(M_PI / 6);
  static_assert(degree2.getRaw() == radian2.getRaw(), "difference: 30 deg <-> pi/6 rad");
  try {
    ics::Angle::newDegree(136);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }

  // runtime test
  auto degree = ics::Angle::newDegree(0);
  auto radian = ics::Angle::newRadian(0);
  assert(degree.getRaw() == radian.getRaw());
  degree.set(90);
  radian.set(M_PI / 2);
  assert(degree.getRaw() == radian.getRaw());
  degree.set(-60);
  radian.set(-M_PI / 3);
  assert(degree.getRaw() == radian.getRaw());
  try {
    degree.set(150);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
  try {
    radian.set(M_PI);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testBaudrate() {
  std::cout << std::endl << "Baudrate test section" << std::endl;
  // constexpr test
  constexpr auto baudrate115200 = ics::Baudrate::RATE115200();
  static_assert(baudrate115200 == 10, "Baudrate: not equal B115200");
  static_assert(baudrate115200.get() == 10, "Baudrate: romdata error");
  static_assert(baudrate115200.getSpeed() == B115200, "Baudrate: getSpeed method error");
}

void testEepParam() {
  std::cout << std::endl << "EepParam test section" << std::endl;
  // constexpr test
  constexpr auto current = ics::EepParam::current();
  static_assert(63 == current.get(), "current error");
  constexpr auto stretch = ics::EepParam::stretch(244);
  static_assert(244 == stretch.get(), "strech error");
  try {
    ics::EepParam::flag(10);
    assert(false);
  } catch (std::invalid_argument& e) {
    std::cout << e.what() << std::endl;
  }

  // runtime test
  auto speed = ics::EepParam::speed();
  assert(127 == speed.get());
  speed.set(100);
  assert(100 == speed.get());
  try {
    speed.set(200);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testID() {
  std::cout << std::endl << "ID test section" << std::endl;
  constexpr ics::ID id {0};
  static_assert(id == 0, "id 0 error");
  static_assert(id.get() == 0, "id 0 error by get");
  constexpr ics::ID id31 {31};
  static_assert(id31 == 31, "id 31 error");
  static_assert(id31.get() == 31, "id 31 error by get");
  try {
    ics::ID id32 {32}; // if constexpr, compile error
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
  try {
    ics::ID error {static_cast<uint8_t>(-1)}; // if constexpr, compile error
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testParameter() {
  std::cout << std::endl << "parameter test section" << std::endl;
  // constexpr test
  constexpr auto stretch = ics::Parameter::stretch();
  static_assert(30 == stretch.get(), "stretch error");
  static_assert(30 == stretch, "stretch error by cast");
  static_assert(0x01 == stretch.getSubcommand(), "stretch error by subcommand");
  constexpr auto speed = ics::Parameter::speed(100);
  static_assert(100 == speed.get(), "speed error");
  static_assert(100 == speed, "speed error by cast");
  static_assert(0x02 == speed.getSubcommand(), "speed error by subcommand");
  try {
    ics::Parameter::temperature(0);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }

  // runtime test
  auto current = ics::Parameter::current();
  assert(63 == current.get());
  assert(0x03 == current.getSubcommand());
  current.set(30);
  assert(30 == current);
  current = 10;
  assert(10 == current);
  try {
    current.set(70);
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
  try {
    current = 64;
    assert(false);
  } catch (std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }
}

void testICS3() {
  std::cout << std::endl << "ICS3 test section" << std::endl;
  constexpr const char*const path = "/dev/ttyUSB0";
  constexpr auto baudrate = ics::Baudrate::RATE115200();
  constexpr ics::ID id {2};
  try {
    ics::ICS3 ics {path, baudrate};
    testIcsMove(ics, id);
    testIcsParam(ics, id);
    testIcsEepRom(ics, id);
  } catch (std::runtime_error& e) {
    std::cout << e.what() << std::endl;
  }
}

void testIcsMove(ics::ICS3& ics, const ics::ID& id) {
  std::cout << "ICS3 'move' and 'free' method test section"  << std::endl;
  auto degree = ics::Angle::newDegree();
  std::cout << "move to " << degree << "[deg]" << std::endl;
  auto nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  degree = 50;
  std::cout << "move to " << degree << "[deg]" << std::endl;
  nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  degree = -50;
  std::cout << "move to " << degree << "[deg]" << std::endl;
  nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  degree = 0;
  std::cout << "move to " << degree << "[deg]" << std::endl;
  nowPos = ics.move(id, degree);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
  std::this_thread::sleep_for(std::chrono::milliseconds(1500));
  std::cout << "free torque" << std::endl;
  nowPos = ics.free(id);
  std::cout << "now pos is " << nowPos << "[deg]" << std::endl;
}

void testIcsParam(ics::ICS3& ics, const ics::ID& id) {
  std::cout << "ICS3 'get' and 'set' method test section"  << std::endl;
  auto defaultStretch = ics.get(id, ics::Parameter::stretch());
  std::cout << "default stretch is " << static_cast<int>(defaultStretch) << std::endl;
  constexpr uint8_t writeNumber {29};
  ics.set(id, ics::Parameter::stretch(writeNumber));
  auto newStretch = ics.get(id, defaultStretch);
  ics.set(id, defaultStretch); // before checking, restore data.
  assert(newStretch == writeNumber);
  assert(defaultStretch == ics.get(id, defaultStretch));
}

void testIcsEepRom(ics::ICS3& ics, const ics::ID& id) {
  std::cout << "ics 'getRom' and 'setRom' test section" << std::endl;
  auto rom = ics.getRom(id);
  auto defaultStretch = rom.get(ics::EepParam::stretch());
  std::cout << "default stretch is " << defaultStretch << std::endl;
  auto setRom = rom;
  constexpr uint16_t writeNumber {62};
  setRom.set(ics::EepParam::stretch(writeNumber));
  ics.setRom(id, setRom);
  auto newRom = ics.getRom(id);
  ics.setRom(id, rom); // before checking, restore data.
  assert(newRom.get(defaultStretch) == writeNumber);
  auto lastRom = ics.getRom(id);
  assert(defaultStretch == lastRom.get(defaultStretch));
}

template<typename Iter>
constexpr void dump(Iter&& begin, Iter&& end) noexcept {
  while (begin != end) std::cout << static_cast<int>(*begin++) << ", ";
  std::cout << std::endl;
}
<|endoftext|>


<commit_before>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   WorldMapModule.cpp
 *  @brief  Simple OpenSim world map module. Listens to region handshake and map block replies.
 *          Draws current region map and avatar positions to widget.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "WorldMapModule.h"
#include "WorldMapWidget.h"

#include "WorldStream.h"
#include "EventManager.h"
#include "RealXtend/RexProtocolMsgIDs.h"
#include "NetworkMessages/NetInMessage.h"
#include "TextureServiceInterface.h"
#include "TextureInterface.h"
#include "AssetEvents.h"
#include "WorldLogicInterface.h"
#include "ConsoleCommandServiceInterface.h"
#include "UiSettingsServiceInterface.h"

#include "EC_OgrePlaceable.h"
#include "EC_OpenSimPresence.h"
#include "SceneManager.h"

#include <Inworld/ControlPanel/TeleportWidget.h>

#include "MemoryLeakCheck.h"

namespace WorldMap
{

    WorldMapModule::WorldMapModule() :
        ModuleInterface(NameStatic()),
        time_from_last_update_ms_(0),
        networkStateEventCategory_(0),
        networkInEventCategory_(0),
        frameworkEventCategory_(0),
        resource_event_category_(0),
        worldmap_widget_(0)
    {
    }

    WorldMapModule::~WorldMapModule()
    {
    }

    void WorldMapModule::Load()
    {
    }

    void WorldMapModule::PostInitialize()
    {
        frameworkEventCategory_ = framework_->GetEventManager()->QueryEventCategory("Framework");
        resource_event_category_ = framework_->GetEventManager()->QueryEventCategory("Resource");

        Foundation::UiSettingsServiceInterface *ui_settings_service = framework_->GetService<Foundation::UiSettingsServiceInterface>();
        if (ui_settings_service)
        {
            CoreUi::TeleportWidget *teleport_widget = dynamic_cast<CoreUi::TeleportWidget*>(ui_settings_service->GetTeleportWidget());
            if (teleport_widget)
            {
                worldmap_widget_ = new WorldMapWidget();
                teleport_widget->InsertMapWidget(worldmap_widget_);
            }
        }
    }

    void WorldMapModule::Update(f64 frametime)
    {
        time_from_last_update_ms_ += frametime;
        if (time_from_last_update_ms_ < 0.5)
            return;
        time_from_last_update_ms_ = 0;

        UpdateAvatarPositions();
    }

    bool WorldMapModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, Foundation::EventDataInterface *data)
    {
        if (category_id == frameworkEventCategory_)
        {
            if (event_id == Foundation::NETWORKING_REGISTERED)
            {
                ProtocolUtilities::NetworkingRegisteredEvent *event_data = checked_static_cast<ProtocolUtilities::NetworkingRegisteredEvent *>(data);
                if (event_data)
                {
                    networkStateEventCategory_ = framework_->GetEventManager()->QueryEventCategory("NetworkState");
                    networkInEventCategory_ = framework_->GetEventManager()->QueryEventCategory("NetworkIn");
                    return false;
                }
            }

            if(event_id == Foundation::WORLD_STREAM_READY)
            {
                ProtocolUtilities::WorldStreamReadyEvent *event_data = checked_static_cast<ProtocolUtilities::WorldStreamReadyEvent *>(data);
                if (event_data)
                    currentWorldStream_ = event_data->WorldStream;

                if (currentWorldStream_)
                    currentWorldStream_->SendMapBlockRequest();

                networkInEventCategory_ = framework_->GetEventManager()->QueryEventCategory("NetworkIn");

                return false;
            }
        }

        if (category_id == networkStateEventCategory_)
        {
            if (event_id == ProtocolUtilities::Events::EVENT_SERVER_CONNECTED)
            {

            }
            else if (event_id == ProtocolUtilities::Events::EVENT_SERVER_DISCONNECTED)
            {
                if (worldmap_widget_)
                    worldmap_widget_->ClearAllContent();
            }
            else if (event_id == ProtocolUtilities::Events::EVENT_USER_DISCONNECTED)
            {
                ProtocolUtilities::UserConnectivityEvent *event_data = checked_static_cast<ProtocolUtilities::UserConnectivityEvent *>(data);
                assert(event_data);
                if (event_data && worldmap_widget_)
                    worldmap_widget_->RemoveAvatar(event_data->agentId.ToQString());
            }
        }

        if (category_id == resource_event_category_)
        {
            HandleResourceEvent(event_id, data);
        }

        if (category_id == networkInEventCategory_)
        {
            using namespace ProtocolUtilities;
            NetworkEventInboundData *netdata = checked_static_cast<NetworkEventInboundData *>(data);
            assert(netdata);
            if (!netdata)
                return false;

            switch(event_id)
            {
                case RexNetMsgMapBlockReply:
                    return HandleOSNE_MapBlock(netdata);
                case RexNetMsgRegionHandshake:
                    return HandleOSNE_RegionHandshake(netdata);
                default:
                    break;
            }
        }

        return false;
    }

    bool WorldMapModule::HandleResourceEvent(event_id_t event_id, Foundation::EventDataInterface* data)
    {

        if (event_id != Resource::Events::RESOURCE_READY)
            return false;

        Resource::Events::ResourceReady *res = dynamic_cast<Resource::Events::ResourceReady*>(data);
        assert(res);
        if (!res)
            return false;

        for(uint index = 0; index < map_asset_requests_.size(); index++)
        {
            if(map_asset_requests_.at(index) == res->tag_)
            {
                Foundation::TextureInterface *tex = dynamic_cast<Foundation::TextureInterface *>(res->resource_.get());
                if(!tex && tex->GetLevel() != 0)
                    return false;

                QImage img = ConvertToQImage(*tex);
                if(worldmap_widget_)
                    worldmap_widget_->StoreMapData(QPixmap::fromImage(img), res->id_.c_str());

            }
        }

        return false;
    }

    bool WorldMapModule::HandleOSNE_MapBlock (ProtocolUtilities::NetworkEventInboundData *data)
    {
        ProtocolUtilities::NetInMessage &msg = *data->message;
        msg.ResetReading();

        RexUUID agent_id = msg.ReadUUID();
        uint32_t flags_ = msg.ReadU32();
        size_t instance_count = msg.ReadCurrentBlockInstanceCount();

        QList<ProtocolUtilities::MapBlock> mapBlocks;
        for (size_t i = 0; i < instance_count; ++i)
        {
            ProtocolUtilities::MapBlock block;
            block.agentID = agent_id;
            block.flags = flags_;
            block.regionX = msg.ReadU16();
            block.regionY = msg.ReadU16();
            block.regionName = msg.ReadString();
            block.access = msg.ReadU8();
            block.regionFlags = msg.ReadU32();
            block.waterHeight = msg.ReadU8();
            block.agents = msg.ReadU8();
            block.mapImageID = msg.ReadUUID();
            mapBlocks.append(block);

            boost::shared_ptr<Foundation::TextureServiceInterface> texture_service = framework_->GetServiceManager()->GetService<Foundation::TextureServiceInterface>(Foundation::Service::ST_Texture).lock();
            if (texture_service)
            {
                texture_service->DeleteFromCache(block.mapImageID.ToString());
                request_tag_t tag = texture_service->RequestTexture(block.mapImageID.ToString());
                if (tag)
                    map_asset_requests_.push_back(tag);
            }
        }

        worldmap_widget_->SetMapBlocks(mapBlocks);
        return false;

    }

    bool WorldMapModule::HandleOSNE_RegionHandshake(ProtocolUtilities::NetworkEventInboundData* data)
    {
        ///\note This message is mostly handled by EnvironmentModule.
        ProtocolUtilities::NetInMessage &msg = *data->message;
        msg.ResetReading();

        msg.SkipToNextVariable(); // RegionFlags U32
        msg.SkipToNextVariable(); // SimAccess U8

        std::string sim_name = msg.ReadString(); // SimName

        if (worldmap_widget_)
        {
            WorldMapModule::LogInfo("WorldMapModule: Set current sim to world map: " + sim_name);
            worldmap_widget_->SetSimName(QString(sim_name.c_str()));
        }

        return false;
    }

    void WorldMapModule::UpdateAvatarPositions()
    {
        if (!worldmap_widget_)
            return;

        Scene::ScenePtr current_scene = framework_->GetDefaultWorldScene();
        if (!current_scene.get())
            return;

        using namespace Foundation;
        if (worldmap_widget_->GetMyAvatarId().isEmpty())
        {
            Scene::EntityPtr my_avatar;
            boost::shared_ptr<WorldLogicInterface> worldLogic = framework_->GetServiceManager()->GetService<WorldLogicInterface>(Service::ST_WorldLogic).lock();
            if (worldLogic)
                my_avatar = worldLogic->GetUserAvatarEntity();

            if (my_avatar)
            {
                EC_OpenSimPresence *user_presence = my_avatar->GetComponent<EC_OpenSimPresence>().get();
                if (user_presence)
                    worldmap_widget_->SetMyAvatarId(user_presence->agentId.ToQString());
            }
        }

        Vector3df top_vector = Vector3df::UNIT_Z, position, direction;

        for(Scene::SceneManager::iterator iter = current_scene->begin(); iter != current_scene->end(); ++iter)
        {
            Scene::Entity &entity = **iter;
            EC_OpenSimPresence *presence_component = entity.GetComponent<EC_OpenSimPresence>().get();
            if (!presence_component)
                continue;

            OgreRenderer::EC_OgrePlaceable *ogre_placeable = entity.GetComponent<OgreRenderer::EC_OgrePlaceable>().get();
            if (ogre_placeable)
            {
                Quaternion q = ogre_placeable->GetOrientation();
                position = ogre_placeable->GetPosition();
                direction = q*Vector3df::UNIT_X;

                worldmap_widget_->UpdateAvatarPosition(position, presence_component->agentId.ToQString(), presence_component->GetFullName().c_str());
            }
        }

    }

    QImage WorldMapModule::ConvertToQImage(Foundation::TextureInterface &tex)
    {
        uint img_width        = tex.GetWidth();
        uint img_height       = tex.GetHeight();
        uint img_components   = tex.GetComponents();
        u8 *data              = tex.GetData();
        uint img_width_step   = img_width * img_components;
        QImage image;

        if(img_width > 0 && img_height > 0 && img_components > 0)
        {
            if(img_components == 3)// For RGB888
            {
                image = QImage(QSize(img_width, img_height), QImage::Format_RGB888);
                for(uint height = 0; height < img_height; height++)
                {
                    for(uint width = 0; width < img_width; width++)
                    {
                        u8 color[3];
                        for(uint comp = 0; comp < img_components; comp++)
                        {
                            uint index = (height % img_height) * (img_width_step) + ((width * img_components) % (img_width_step)) + comp;
                            color[comp] = data[index];
                        }
                        image.setPixel(width, height, qRgb(color[0], color[1], color[2]));
                    }
                }
            }
            else if(img_components == 4)// For ARGB32
            {
                image = QImage(QSize(img_width, img_height), QImage::Format_ARGB32);
                for(uint height = 0; height < img_height; height++)
                {
                    for(uint width = 0; width < img_width; width++)
                    {
                        u8 color[4];
                        for(uint comp = 0; comp < img_components; comp++)
                        {
                            uint index = (height % img_height) * (img_width_step) + ((width * img_components) % (img_width_step)) + comp;
                            color[comp] = data[index];
                        }
                        image.setPixel(width, height, qRgba(color[0], color[1], color[2], color[3]));
                    }
                }
            }
        }

        return image;
    }

    const std::string WorldMapModule::moduleName = std::string("WorldMapModule");

    const std::string &WorldMapModule::NameStatic()
    {
        return moduleName;
    }

    extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
    void SetProfiler(Foundation::Profiler *profiler)
    {
        Foundation::ProfilerSection::SetProfiler(profiler);
    }

}

using namespace WorldMap;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
    POCO_EXPORT_CLASS(WorldMapModule)
POCO_END_MANIFEST
<commit_msg>gcc build fix, char* is not accepted where QString is expected<commit_after>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   WorldMapModule.cpp
 *  @brief  Simple OpenSim world map module. Listens to region handshake and map block replies.
 *          Draws current region map and avatar positions to widget.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "WorldMapModule.h"
#include "WorldMapWidget.h"

#include "WorldStream.h"
#include "EventManager.h"
#include "RealXtend/RexProtocolMsgIDs.h"
#include "NetworkMessages/NetInMessage.h"
#include "TextureServiceInterface.h"
#include "TextureInterface.h"
#include "AssetEvents.h"
#include "WorldLogicInterface.h"
#include "ConsoleCommandServiceInterface.h"
#include "UiSettingsServiceInterface.h"

#include "EC_OgrePlaceable.h"
#include "EC_OpenSimPresence.h"
#include "SceneManager.h"

#include <Inworld/ControlPanel/TeleportWidget.h>

#include "MemoryLeakCheck.h"

namespace WorldMap
{

    WorldMapModule::WorldMapModule() :
        ModuleInterface(NameStatic()),
        time_from_last_update_ms_(0),
        networkStateEventCategory_(0),
        networkInEventCategory_(0),
        frameworkEventCategory_(0),
        resource_event_category_(0),
        worldmap_widget_(0)
    {
    }

    WorldMapModule::~WorldMapModule()
    {
    }

    void WorldMapModule::Load()
    {
    }

    void WorldMapModule::PostInitialize()
    {
        frameworkEventCategory_ = framework_->GetEventManager()->QueryEventCategory("Framework");
        resource_event_category_ = framework_->GetEventManager()->QueryEventCategory("Resource");

        Foundation::UiSettingsServiceInterface *ui_settings_service = framework_->GetService<Foundation::UiSettingsServiceInterface>();
        if (ui_settings_service)
        {
            CoreUi::TeleportWidget *teleport_widget = dynamic_cast<CoreUi::TeleportWidget*>(ui_settings_service->GetTeleportWidget());
            if (teleport_widget)
            {
                worldmap_widget_ = new WorldMapWidget();
                teleport_widget->InsertMapWidget(worldmap_widget_);
            }
        }
    }

    void WorldMapModule::Update(f64 frametime)
    {
        time_from_last_update_ms_ += frametime;
        if (time_from_last_update_ms_ < 0.5)
            return;
        time_from_last_update_ms_ = 0;

        UpdateAvatarPositions();
    }

    bool WorldMapModule::HandleEvent(event_category_id_t category_id, event_id_t event_id, Foundation::EventDataInterface *data)
    {
        if (category_id == frameworkEventCategory_)
        {
            if (event_id == Foundation::NETWORKING_REGISTERED)
            {
                ProtocolUtilities::NetworkingRegisteredEvent *event_data = checked_static_cast<ProtocolUtilities::NetworkingRegisteredEvent *>(data);
                if (event_data)
                {
                    networkStateEventCategory_ = framework_->GetEventManager()->QueryEventCategory("NetworkState");
                    networkInEventCategory_ = framework_->GetEventManager()->QueryEventCategory("NetworkIn");
                    return false;
                }
            }

            if(event_id == Foundation::WORLD_STREAM_READY)
            {
                ProtocolUtilities::WorldStreamReadyEvent *event_data = checked_static_cast<ProtocolUtilities::WorldStreamReadyEvent *>(data);
                if (event_data)
                    currentWorldStream_ = event_data->WorldStream;

                if (currentWorldStream_)
                    currentWorldStream_->SendMapBlockRequest();

                networkInEventCategory_ = framework_->GetEventManager()->QueryEventCategory("NetworkIn");

                return false;
            }
        }

        if (category_id == networkStateEventCategory_)
        {
            if (event_id == ProtocolUtilities::Events::EVENT_SERVER_CONNECTED)
            {

            }
            else if (event_id == ProtocolUtilities::Events::EVENT_SERVER_DISCONNECTED)
            {
                if (worldmap_widget_)
                    worldmap_widget_->ClearAllContent();
            }
            else if (event_id == ProtocolUtilities::Events::EVENT_USER_DISCONNECTED)
            {
                ProtocolUtilities::UserConnectivityEvent *event_data = checked_static_cast<ProtocolUtilities::UserConnectivityEvent *>(data);
                assert(event_data);
                if (event_data && worldmap_widget_)
                    worldmap_widget_->RemoveAvatar(event_data->agentId.ToQString());
            }
        }

        if (category_id == resource_event_category_)
        {
            HandleResourceEvent(event_id, data);
        }

        if (category_id == networkInEventCategory_)
        {
            using namespace ProtocolUtilities;
            NetworkEventInboundData *netdata = checked_static_cast<NetworkEventInboundData *>(data);
            assert(netdata);
            if (!netdata)
                return false;

            switch(event_id)
            {
                case RexNetMsgMapBlockReply:
                    return HandleOSNE_MapBlock(netdata);
                case RexNetMsgRegionHandshake:
                    return HandleOSNE_RegionHandshake(netdata);
                default:
                    break;
            }
        }

        return false;
    }

    bool WorldMapModule::HandleResourceEvent(event_id_t event_id, Foundation::EventDataInterface* data)
    {

        if (event_id != Resource::Events::RESOURCE_READY)
            return false;

        Resource::Events::ResourceReady *res = dynamic_cast<Resource::Events::ResourceReady*>(data);
        assert(res);
        if (!res)
            return false;

        for(uint index = 0; index < map_asset_requests_.size(); index++)
        {
            if(map_asset_requests_.at(index) == res->tag_)
            {
                Foundation::TextureInterface *tex = dynamic_cast<Foundation::TextureInterface *>(res->resource_.get());
                if(!tex && tex->GetLevel() != 0)
                    return false;

                QImage img = ConvertToQImage(*tex);
                if(worldmap_widget_)
                    worldmap_widget_->StoreMapData(QPixmap::fromImage(img), QString(res->id_.c_str()));

            }
        }

        return false;
    }

    bool WorldMapModule::HandleOSNE_MapBlock (ProtocolUtilities::NetworkEventInboundData *data)
    {
        ProtocolUtilities::NetInMessage &msg = *data->message;
        msg.ResetReading();

        RexUUID agent_id = msg.ReadUUID();
        uint32_t flags_ = msg.ReadU32();
        size_t instance_count = msg.ReadCurrentBlockInstanceCount();

        QList<ProtocolUtilities::MapBlock> mapBlocks;
        for (size_t i = 0; i < instance_count; ++i)
        {
            ProtocolUtilities::MapBlock block;
            block.agentID = agent_id;
            block.flags = flags_;
            block.regionX = msg.ReadU16();
            block.regionY = msg.ReadU16();
            block.regionName = msg.ReadString();
            block.access = msg.ReadU8();
            block.regionFlags = msg.ReadU32();
            block.waterHeight = msg.ReadU8();
            block.agents = msg.ReadU8();
            block.mapImageID = msg.ReadUUID();
            mapBlocks.append(block);

            boost::shared_ptr<Foundation::TextureServiceInterface> texture_service = framework_->GetServiceManager()->GetService<Foundation::TextureServiceInterface>(Foundation::Service::ST_Texture).lock();
            if (texture_service)
            {
                texture_service->DeleteFromCache(block.mapImageID.ToString());
                request_tag_t tag = texture_service->RequestTexture(block.mapImageID.ToString());
                if (tag)
                    map_asset_requests_.push_back(tag);
            }
        }

        worldmap_widget_->SetMapBlocks(mapBlocks);
        return false;

    }

    bool WorldMapModule::HandleOSNE_RegionHandshake(ProtocolUtilities::NetworkEventInboundData* data)
    {
        ///\note This message is mostly handled by EnvironmentModule.
        ProtocolUtilities::NetInMessage &msg = *data->message;
        msg.ResetReading();

        msg.SkipToNextVariable(); // RegionFlags U32
        msg.SkipToNextVariable(); // SimAccess U8

        std::string sim_name = msg.ReadString(); // SimName

        if (worldmap_widget_)
        {
            WorldMapModule::LogInfo("WorldMapModule: Set current sim to world map: " + sim_name);
            worldmap_widget_->SetSimName(QString(sim_name.c_str()));
        }

        return false;
    }

    void WorldMapModule::UpdateAvatarPositions()
    {
        if (!worldmap_widget_)
            return;

        Scene::ScenePtr current_scene = framework_->GetDefaultWorldScene();
        if (!current_scene.get())
            return;

        using namespace Foundation;
        if (worldmap_widget_->GetMyAvatarId().isEmpty())
        {
            Scene::EntityPtr my_avatar;
            boost::shared_ptr<WorldLogicInterface> worldLogic = framework_->GetServiceManager()->GetService<WorldLogicInterface>(Service::ST_WorldLogic).lock();
            if (worldLogic)
                my_avatar = worldLogic->GetUserAvatarEntity();

            if (my_avatar)
            {
                EC_OpenSimPresence *user_presence = my_avatar->GetComponent<EC_OpenSimPresence>().get();
                if (user_presence)
                    worldmap_widget_->SetMyAvatarId(user_presence->agentId.ToQString());
            }
        }

        Vector3df top_vector = Vector3df::UNIT_Z, position, direction;

        for(Scene::SceneManager::iterator iter = current_scene->begin(); iter != current_scene->end(); ++iter)
        {
            Scene::Entity &entity = **iter;
            EC_OpenSimPresence *presence_component = entity.GetComponent<EC_OpenSimPresence>().get();
            if (!presence_component)
                continue;

            OgreRenderer::EC_OgrePlaceable *ogre_placeable = entity.GetComponent<OgreRenderer::EC_OgrePlaceable>().get();
            if (ogre_placeable)
            {
                Quaternion q = ogre_placeable->GetOrientation();
                position = ogre_placeable->GetPosition();
                direction = q*Vector3df::UNIT_X;

                worldmap_widget_->UpdateAvatarPosition(position, presence_component->agentId.ToQString(), presence_component->GetFullName().c_str());
            }
        }

    }

    QImage WorldMapModule::ConvertToQImage(Foundation::TextureInterface &tex)
    {
        uint img_width        = tex.GetWidth();
        uint img_height       = tex.GetHeight();
        uint img_components   = tex.GetComponents();
        u8 *data              = tex.GetData();
        uint img_width_step   = img_width * img_components;
        QImage image;

        if(img_width > 0 && img_height > 0 && img_components > 0)
        {
            if(img_components == 3)// For RGB888
            {
                image = QImage(QSize(img_width, img_height), QImage::Format_RGB888);
                for(uint height = 0; height < img_height; height++)
                {
                    for(uint width = 0; width < img_width; width++)
                    {
                        u8 color[3];
                        for(uint comp = 0; comp < img_components; comp++)
                        {
                            uint index = (height % img_height) * (img_width_step) + ((width * img_components) % (img_width_step)) + comp;
                            color[comp] = data[index];
                        }
                        image.setPixel(width, height, qRgb(color[0], color[1], color[2]));
                    }
                }
            }
            else if(img_components == 4)// For ARGB32
            {
                image = QImage(QSize(img_width, img_height), QImage::Format_ARGB32);
                for(uint height = 0; height < img_height; height++)
                {
                    for(uint width = 0; width < img_width; width++)
                    {
                        u8 color[4];
                        for(uint comp = 0; comp < img_components; comp++)
                        {
                            uint index = (height % img_height) * (img_width_step) + ((width * img_components) % (img_width_step)) + comp;
                            color[comp] = data[index];
                        }
                        image.setPixel(width, height, qRgba(color[0], color[1], color[2], color[3]));
                    }
                }
            }
        }

        return image;
    }

    const std::string WorldMapModule::moduleName = std::string("WorldMapModule");

    const std::string &WorldMapModule::NameStatic()
    {
        return moduleName;
    }

    extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
    void SetProfiler(Foundation::Profiler *profiler)
    {
        Foundation::ProfilerSection::SetProfiler(profiler);
    }

}

using namespace WorldMap;

POCO_BEGIN_MANIFEST(Foundation::ModuleInterface)
    POCO_EXPORT_CLASS(WorldMapModule)
POCO_END_MANIFEST
<|endoftext|>